258 lines
9.9 KiB
Bash
Executable File
258 lines
9.9 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
umask 077
|
|
|
|
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
|
domain=${1:-}
|
|
target=${2:-"$ROOT/.env.production"}
|
|
|
|
usage() {
|
|
echo "Usage: $0 DOMAIN [OUTPUT_FILE]" >&2
|
|
}
|
|
|
|
if [ -z "$domain" ]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
if ! printf '%s\n' "$domain" |
|
|
grep -Eq '^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$'; then
|
|
echo "DOMAIN must be a lowercase ASCII DNS hostname without a scheme, port, or path." >&2
|
|
exit 1
|
|
fi
|
|
|
|
for command in awk docker grep mktemp openssl stat; do
|
|
if ! command -v "$command" >/dev/null 2>&1; then
|
|
echo "Required command is unavailable: $command" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
if [ ! -S /var/run/docker.sock ]; then
|
|
echo "/var/run/docker.sock is unavailable; run this on the target Docker host." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ -e "$target" ]; then
|
|
echo "Refusing to overwrite existing deployment environment: $target" >&2
|
|
exit 1
|
|
fi
|
|
|
|
target_dir=$(dirname -- "$target")
|
|
if [ ! -d "$target_dir" ]; then
|
|
echo "Output directory does not exist: $target_dir" >&2
|
|
exit 1
|
|
fi
|
|
|
|
database_mode=${PRODUCTION_DATABASE_MODE:-container}
|
|
app_topology=${PRODUCTION_APP_TOPOLOGY:-compact}
|
|
compose_project_name=${PRODUCTION_COMPOSE_PROJECT_NAME:-who_need_help}
|
|
public_edge_enabled=${PRODUCTION_PUBLIC_EDGE_ENABLED:-true}
|
|
public_edge_network=${PRODUCTION_PUBLIC_EDGE_NETWORK:-who_need_help_public_edge}
|
|
public_upstream_name=${PRODUCTION_PUBLIC_UPSTREAM_NAME:-who-need-help-production}
|
|
codex_session_id=${PRODUCTION_CODEX_SESSION_ID:-}
|
|
|
|
if [ -z "$codex_session_id" ]; then
|
|
echo "PRODUCTION_CODEX_SESSION_ID is required for the Build Week feedback page." >&2
|
|
exit 1
|
|
fi
|
|
|
|
case "$compose_project_name" in
|
|
*[!a-zA-Z0-9_-]* | '')
|
|
echo "PRODUCTION_COMPOSE_PROJECT_NAME must contain only letters, numbers, underscores, or hyphens." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
case "$database_mode" in
|
|
container)
|
|
postgres_password=$(openssl rand -hex 32)
|
|
database_url="ecto://postgres:$postgres_password@db/who_need_help"
|
|
;;
|
|
external)
|
|
postgres_password=
|
|
database_url=${PRODUCTION_DATABASE_URL:-}
|
|
if [ -z "$database_url" ]; then
|
|
echo "PRODUCTION_DATABASE_URL is required when PRODUCTION_DATABASE_MODE=external." >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "PRODUCTION_DATABASE_MODE must be container or external." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
database_socket_dir=${PRODUCTION_DATABASE_SOCKET_DIR:-}
|
|
if [ -n "$database_socket_dir" ]; then
|
|
case "$database_socket_dir" in
|
|
/*) ;;
|
|
*) echo "PRODUCTION_DATABASE_SOCKET_DIR must be an absolute path." >&2; exit 1 ;;
|
|
esac
|
|
|
|
if [ "$database_mode" != external ]; then
|
|
echo "PRODUCTION_DATABASE_SOCKET_DIR is only valid when PRODUCTION_DATABASE_MODE=external." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
case "$app_topology" in
|
|
compact | split) ;;
|
|
*) echo "PRODUCTION_APP_TOPOLOGY must be compact or split." >&2; exit 1 ;;
|
|
esac
|
|
|
|
case "$public_edge_enabled" in
|
|
true | false) ;;
|
|
*) echo "PRODUCTION_PUBLIC_EDGE_ENABLED must be true or false." >&2; exit 1 ;;
|
|
esac
|
|
|
|
secret_key_base=$(openssl rand -hex 64)
|
|
handover_secret=$(openssl rand -hex 64)
|
|
release_cookie=$(openssl rand -hex 64)
|
|
metrics_token=$(openssl rand -hex 32)
|
|
docker_socket_gid=$(stat -c '%g' /var/run/docker.sock)
|
|
|
|
http_bind_address=${PRODUCTION_HTTP_BIND_ADDRESS:-127.0.0.1}
|
|
http_port=${PRODUCTION_HTTP_PORT:-4010}
|
|
trusted_proxy_ips=${PRODUCTION_TRAEFIK_TRUSTED_IPS:-REPLACE_WITH_VERIFIED_PROXY_IP_OR_CIDR}
|
|
email_delivery_provider=${PRODUCTION_EMAIL_DELIVERY_PROVIDER:-smtp}
|
|
smtp_relay=${PRODUCTION_SMTP_RELAY:-REPLACE_WITH_TRANSACTIONAL_SMTP_RELAY}
|
|
smtp_port=${PRODUCTION_SMTP_PORT:-587}
|
|
smtp_username=${PRODUCTION_SMTP_USERNAME:-}
|
|
smtp_password=${PRODUCTION_SMTP_PASSWORD:-}
|
|
smtp_auth=${PRODUCTION_SMTP_AUTH:-always}
|
|
smtp_tls=${PRODUCTION_SMTP_TLS:-always}
|
|
smtp_ssl=${PRODUCTION_SMTP_SSL:-false}
|
|
unisender_go_api_key=${PRODUCTION_UNISENDER_GO_API_KEY:-}
|
|
unisender_go_base_url=${PRODUCTION_UNISENDER_GO_BASE_URL:-https://goapi.unisender.ru/ru/transactional/api/v1}
|
|
unisender_go_skip_unsubscribe=${PRODUCTION_UNISENDER_GO_SKIP_UNSUBSCRIBE:-false}
|
|
email_http_connect_timeout_ms=${PRODUCTION_EMAIL_HTTP_CONNECT_TIMEOUT_MS:-}
|
|
email_http_receive_timeout_ms=${PRODUCTION_EMAIL_HTTP_RECEIVE_TIMEOUT_MS:-}
|
|
email_from_address=${PRODUCTION_EMAIL_FROM_ADDRESS:-"contact@$domain"}
|
|
support_inbox_address=${PRODUCTION_SUPPORT_INBOX_ADDRESS:-}
|
|
|
|
case "$email_delivery_provider" in
|
|
smtp) ;;
|
|
unisender_go)
|
|
if [ -z "$unisender_go_api_key" ]; then
|
|
echo "PRODUCTION_UNISENDER_GO_API_KEY is required for the unisender_go email provider." >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "PRODUCTION_EMAIL_DELIVERY_PROVIDER must be smtp or unisender_go." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
case "$unisender_go_skip_unsubscribe" in
|
|
true | false) ;;
|
|
*) echo "PRODUCTION_UNISENDER_GO_SKIP_UNSUBSCRIBE must be true or false." >&2; exit 1 ;;
|
|
esac
|
|
|
|
tmp=$(mktemp "$target_dir/.production-env.XXXXXX")
|
|
trap 'rm -f "$tmp"' EXIT HUP INT TERM
|
|
chmod 600 "$tmp"
|
|
|
|
DOMAIN=$domain \
|
|
DATABASE_MODE_VALUE=$database_mode \
|
|
APP_TOPOLOGY_VALUE=$app_topology \
|
|
COMPOSE_PROJECT_NAME_VALUE=$compose_project_name \
|
|
HTTP_BIND_ADDRESS_VALUE=$http_bind_address \
|
|
HTTP_PORT_VALUE=$http_port \
|
|
PUBLIC_EDGE_ENABLED_VALUE=$public_edge_enabled \
|
|
PUBLIC_EDGE_NETWORK_VALUE=$public_edge_network \
|
|
PUBLIC_UPSTREAM_NAME_VALUE=$public_upstream_name \
|
|
DOCKER_SOCKET_GID_VALUE=$docker_socket_gid \
|
|
TRUSTED_PROXY_IPS_VALUE=$trusted_proxy_ips \
|
|
POSTGRES_PASSWORD_VALUE=$postgres_password \
|
|
DATABASE_URL_VALUE=$database_url \
|
|
DATABASE_SOCKET_DIR_VALUE=$database_socket_dir \
|
|
SECRET_KEY_BASE_VALUE=$secret_key_base \
|
|
HANDOVER_SECRET_VALUE=$handover_secret \
|
|
RELEASE_COOKIE_VALUE=$release_cookie \
|
|
METRICS_TOKEN_VALUE=$metrics_token \
|
|
EMAIL_DELIVERY_PROVIDER_VALUE=$email_delivery_provider \
|
|
SMTP_RELAY_VALUE=$smtp_relay \
|
|
SMTP_PORT_VALUE=$smtp_port \
|
|
SMTP_USERNAME_VALUE=$smtp_username \
|
|
SMTP_PASSWORD_VALUE=$smtp_password \
|
|
SMTP_AUTH_VALUE=$smtp_auth \
|
|
SMTP_TLS_VALUE=$smtp_tls \
|
|
SMTP_SSL_VALUE=$smtp_ssl \
|
|
UNISENDER_GO_API_KEY_VALUE=$unisender_go_api_key \
|
|
UNISENDER_GO_BASE_URL_VALUE=$unisender_go_base_url \
|
|
UNISENDER_GO_SKIP_UNSUBSCRIBE_VALUE=$unisender_go_skip_unsubscribe \
|
|
EMAIL_HTTP_CONNECT_TIMEOUT_MS_VALUE=$email_http_connect_timeout_ms \
|
|
EMAIL_HTTP_RECEIVE_TIMEOUT_MS_VALUE=$email_http_receive_timeout_ms \
|
|
EMAIL_FROM_ADDRESS_VALUE=$email_from_address \
|
|
SUPPORT_INBOX_ADDRESS_VALUE=$support_inbox_address \
|
|
CODEX_SESSION_ID_VALUE=$codex_session_id \
|
|
awk '
|
|
BEGIN {
|
|
replacement["DEPLOYMENT_TARGET"] = "compose"
|
|
replacement["DEPLOYMENT_ENV"] = "production"
|
|
replacement["COMPOSE_PROJECT_NAME"] = ENVIRON["COMPOSE_PROJECT_NAME_VALUE"]
|
|
replacement["APP_TOPOLOGY"] = ENVIRON["APP_TOPOLOGY_VALUE"]
|
|
replacement["DATABASE_MODE"] = ENVIRON["DATABASE_MODE_VALUE"]
|
|
replacement["HTTP_BIND_ADDRESS"] = ENVIRON["HTTP_BIND_ADDRESS_VALUE"]
|
|
replacement["HTTP_PORT"] = ENVIRON["HTTP_PORT_VALUE"]
|
|
replacement["PUBLIC_EDGE_ENABLED"] = ENVIRON["PUBLIC_EDGE_ENABLED_VALUE"]
|
|
replacement["PUBLIC_EDGE_NETWORK"] = ENVIRON["PUBLIC_EDGE_NETWORK_VALUE"]
|
|
replacement["PUBLIC_UPSTREAM_NAME"] = ENVIRON["PUBLIC_UPSTREAM_NAME_VALUE"]
|
|
replacement["DOCKER_SOCKET_GID"] = ENVIRON["DOCKER_SOCKET_GID_VALUE"]
|
|
replacement["TRAEFIK_TRUSTED_IPS"] = ENVIRON["TRUSTED_PROXY_IPS_VALUE"]
|
|
replacement["TRAEFIK_PROJECT_CONSTRAINT"] = ENVIRON["COMPOSE_PROJECT_NAME_VALUE"]
|
|
replacement["TRAEFIK_DOCKER_NETWORK"] = ENVIRON["COMPOSE_PROJECT_NAME_VALUE"] "_ingress"
|
|
replacement["PHX_HOST"] = ENVIRON["DOMAIN"]
|
|
replacement["PHX_SCHEME"] = "https"
|
|
replacement["PHX_URL_PORT"] = "443"
|
|
replacement["WNH_DEBUG_BASE_URL"] = "https://" ENVIRON["DOMAIN"]
|
|
replacement["WNH_BASE_URL"] = "https://" ENVIRON["DOMAIN"]
|
|
replacement["POSTGRES_PASSWORD"] = ENVIRON["POSTGRES_PASSWORD_VALUE"]
|
|
replacement["DATABASE_URL"] = ENVIRON["DATABASE_URL_VALUE"]
|
|
replacement["DATABASE_SOCKET_DIR"] = ENVIRON["DATABASE_SOCKET_DIR_VALUE"]
|
|
replacement["SECRET_KEY_BASE"] = ENVIRON["SECRET_KEY_BASE_VALUE"]
|
|
replacement["HANDOVER_SECRET"] = ENVIRON["HANDOVER_SECRET_VALUE"]
|
|
replacement["RELEASE_COOKIE"] = ENVIRON["RELEASE_COOKIE_VALUE"]
|
|
replacement["METRICS_TOKEN"] = ENVIRON["METRICS_TOKEN_VALUE"]
|
|
replacement["EMAIL_DELIVERY_PROVIDER"] = ENVIRON["EMAIL_DELIVERY_PROVIDER_VALUE"]
|
|
replacement["SMTP_RELAY"] = ENVIRON["SMTP_RELAY_VALUE"]
|
|
replacement["SMTP_PORT"] = ENVIRON["SMTP_PORT_VALUE"]
|
|
replacement["SMTP_USERNAME"] = ENVIRON["SMTP_USERNAME_VALUE"]
|
|
replacement["SMTP_PASSWORD"] = ENVIRON["SMTP_PASSWORD_VALUE"]
|
|
replacement["SMTP_AUTH"] = ENVIRON["SMTP_AUTH_VALUE"]
|
|
replacement["SMTP_TLS"] = ENVIRON["SMTP_TLS_VALUE"]
|
|
replacement["SMTP_SSL"] = ENVIRON["SMTP_SSL_VALUE"]
|
|
replacement["UNISENDER_GO_API_KEY"] = ENVIRON["UNISENDER_GO_API_KEY_VALUE"]
|
|
replacement["UNISENDER_GO_BASE_URL"] = ENVIRON["UNISENDER_GO_BASE_URL_VALUE"]
|
|
replacement["UNISENDER_GO_SKIP_UNSUBSCRIBE"] = ENVIRON["UNISENDER_GO_SKIP_UNSUBSCRIBE_VALUE"]
|
|
replacement["EMAIL_HTTP_CONNECT_TIMEOUT_MS"] = ENVIRON["EMAIL_HTTP_CONNECT_TIMEOUT_MS_VALUE"]
|
|
replacement["EMAIL_HTTP_RECEIVE_TIMEOUT_MS"] = ENVIRON["EMAIL_HTTP_RECEIVE_TIMEOUT_MS_VALUE"]
|
|
replacement["EMAIL_FROM_ADDRESS"] = ENVIRON["EMAIL_FROM_ADDRESS_VALUE"]
|
|
replacement["SUPPORT_INBOX_ADDRESS"] = ENVIRON["SUPPORT_INBOX_ADDRESS_VALUE"]
|
|
replacement["CODEX_SESSION_ID"] = ENVIRON["CODEX_SESSION_ID_VALUE"]
|
|
}
|
|
{
|
|
separator = index($0, "=")
|
|
key = separator > 1 ? substr($0, 1, separator - 1) : ""
|
|
|
|
if (key in replacement) {
|
|
print key "=" replacement[key]
|
|
} else {
|
|
print
|
|
}
|
|
}
|
|
' "$ROOT/.env.example" >"$tmp"
|
|
|
|
mv "$tmp" "$target"
|
|
chmod 600 "$target"
|
|
trap - EXIT HUP INT TERM
|
|
|
|
unset postgres_password secret_key_base handover_secret release_cookie metrics_token
|
|
unset smtp_password unisender_go_api_key
|
|
|
|
echo "Generated independent deployment secrets without printing them."
|
|
echo "Created mode-0600 environment: $target"
|
|
echo "Run scripts/validate-production-env.sh '$target' '$domain' after configuring the verified proxy and email-provider values."
|