#!/bin/bash # stop if something fails set -euo pipefail log_error() { local message="$1" echo -e "\e[31m$message\e[0m" # red in console } # called always on error, log error really visible with ascii art in red on console and html # stop script execution onError() { local exit_code=$? log_error "Command failed!" log_error " /\\_/\\ Line: $(caller 0)" log_error "( x.x ) Exit Code: $exit_code" log_error " > < Offending command: '$BASH_COMMAND'" log_error "" exit 1 } trap onError ERR # check for parameter if [ -z "$1" ]; then log_error "Usage: Please provide a branch name as the first argument." exit 1 fi # Note: This is needed - since there is Summer-Time included in the default server Setup - UTC is REQUIRED for production data timedatectl set-timezone UTC timedatectl set-ntp on apt purge ntp systemctl start systemd-timesyncd set -o allexport SCRIPT_PATH=$(realpath ../bare_metal) SCRIPT_DIR=$(dirname $SCRIPT_PATH) LOCAL_SCRIPT_PATH=$(realpath $0) LOCAL_SCRIPT_DIR=$(dirname $LOCAL_SCRIPT_PATH) PROJECT_ROOT=$SCRIPT_DIR/.. set +o allexport # Replace placeholder secrets in .env echo 'Replace placeholder secrets in .env' # Load .env or .env.dist if not present # NOTE: all config values will be in process.env when starting # the services and will therefore take precedence over the .env if [ -f "$SCRIPT_PATH/.env" ]; then ENV_FILE="$SCRIPT_PATH/.env" # --- Secret Generators ------------------------------------------------------- gen_jwt_secret() { # 32 Character, URL-safe: A-Z a-z 0-9 _ - tr -dc 'A-Za-z0-9_-' < /dev/urandom | head -c 32 2>/dev/null || true } gen_webhook_secret() { # URL-safe, longer security (40 chars) tr -dc 'A-Za-z0-9_-' < /dev/urandom | head -c 40 2>/dev/null || true } gen_binary_secret() { local bytes="$1" # Hex -> 2 chars pro byte openssl rand -hex "$bytes" 2>/dev/null || true } # --- Mapping of Placeholder -> Function -------------------------------------- generate_secret_for() { case "$1" in jwt_secret) gen_jwt_secret ;; webhook_secret) gen_webhook_secret ;; binary8_secret) gen_binary_secret 8 ;; binary16_secret) gen_binary_secret 16;; binary32_secret) gen_binary_secret 32;; *) echo "Unknown Placeholder: $1" >&2 exit 1 ;; esac } # --- Placeholder List -------------------------------------------------------- placeholders=( "jwt_secret" "webhook_secret" "binary8_secret" "binary16_secret" "binary32_secret" ) # --- Processing in .env ------------------------------------------------- TMP_FILE="${ENV_FILE}.tmp" cp "$ENV_FILE" "$TMP_FILE" for ph in "${placeholders[@]}"; do # Iterate over all lines containing the placeholder while grep -q "$ph" "$TMP_FILE"; do new_value=$(generate_secret_for "$ph") # Replace only the first occurrence per line sed -i "0,/$ph/s//$new_value/" "$TMP_FILE" done done # Write back mv "$TMP_FILE" "$ENV_FILE" chown gradido:gradido "$ENV_FILE" fi # If install.sh will be called more than once # We have to load the backend .env to get DB_USERNAME and DB_PASSWORD export_var(){ export $1=$(grep -v '^#' $PROJECT_ROOT/backend/.env | grep -e "$1" | sed -e 's/.*=//') } if [ -f "$PROJECT_ROOT/backend/.env" ]; then export_var 'DB_USER' export_var 'DB_PASSWORD' fi # Load .env or .env.dist if not present # NOTE: all config values will be in process.env when starting # the services and will therefore take precedence over the .env if [ -f "$SCRIPT_PATH/.env" ]; then set -o allexport source $SCRIPT_PATH/.env set +o allexport else set -o allexport source $SCRIPT_PATH/.env.dist set +o allexport fi # Configure git git config pull.ff only # Secure mysql https://gist.github.com/Mins/4602864 SECURE_MYSQL=$(expect -c " set timeout 10 spawn mysql_secure_installation expect \"Enter current password for root (enter for none):\" send \"\r\" expect \"Switch to unix_socket authentication:\" send \"Y\r\" expect \"Change the root password?\" send \"n\r\" expect \"Remove anonymous users?\" send \"y\r\" expect \"Disallow root login remotely?\" send \"y\r\" expect \"Remove test database and access to it?\" send \"y\r\" expect \"Reload privilege tables now?\" send \"y\r\" expect eof ") echo "$SECURE_MYSQL" # Configure fail2ban, seems to not run out of the box on Debian 12 echo -e "[sshd]\nbackend = systemd" | tee /etc/fail2ban/jail.d/sshd.conf # enable nginx-limit-req filter to block also user which exceed nginx request limiter echo -e "[nginx-limit-req]\nenabled = true\nlogpath = $SCRIPT_PATH/log/nginx-error.*.log" | tee /etc/fail2ban/jail.d/nginx-limit-req.conf # enable nginx bad request filter echo -e "[nginx-bad-request]\nenabled = true\nlogpath = $SCRIPT_PATH/log/nginx-error.*.log" | tee /etc/fail2ban/jail.d/nginx-bad-request.conf systemctl restart fail2ban # Configure nginx rm /etc/nginx/sites-enabled/default envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/update-page.conf.template > $SCRIPT_PATH/nginx/sites-available/update-page.conf mkdir -p $SCRIPT_PATH/nginx/sites-enabled ln -sf $SCRIPT_PATH/nginx/sites-available/update-page.conf $SCRIPT_PATH/nginx/sites-enabled/default ln -sf $SCRIPT_PATH/nginx/sites-enabled/default /etc/nginx/sites-enabled ln -sf $SCRIPT_PATH/nginx/common /etc/nginx/ if [ -e /etc/nginx/conf.d ] && [ ! -L /etc/nginx/conf.d ]; then rm -rf /etc/nginx/conf.d ln -s $SCRIPT_PATH/nginx/conf.d /etc/nginx/ fi # Make nginx restart automatic mkdir -p /etc/systemd/system/nginx.service.d # Define the content to be put into the override.conf file CONFIG_CONTENT="[Unit] StartLimitIntervalSec=500 StartLimitBurst=5 [Service] Restart=on-failure RestartSec=5s" # Write the content to the override.conf file echo "$CONFIG_CONTENT" | sudo tee /etc/systemd/system/nginx.service.d/override.conf >/dev/null # Reload systemd to apply the changes sudo systemctl daemon-reload # setup https with certbot certbot certonly --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST --email $COMMUNITY_SUPPORT_MAIL export NVM_DIR="/home/gradido/.nvm" BUN_VERSION_FILE="$PROJECT_ROOT/.bun-version" if [ ! -f "$BUN_VERSION_FILE" ]; then echo ".bun-version file not found at: $BUN_VERSION_FILE" exit 1 fi export BUN_VERSION="$(cat "$BUN_VERSION_FILE" | tr -d '[:space:]')" export BUN_INSTALL="/home/gradido/.bun" # run as gradido user (until EOF) sudo -u gradido bash </dev/null 2>&1; then nvm install fi # Install pm2 and turbo npm i -g pm2 turbo echo "'bun' v$BUN_VERSION will be installed now!" curl -fsSL https://bun.com/install | bash -s "bun-v${BUN_VERSION}" EOF # Load bun export BUN_INSTALL="/home/gradido/.bun" export PATH="$BUN_INSTALL/bin:$PATH" # Load nvm export NVM_DIR="/home/gradido/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # start pm2 pm2 startup # Install logrotate envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/logrotate/gradido.conf.template > $SCRIPT_PATH/logrotate/gradido.conf cp $SCRIPT_PATH/logrotate/gradido.conf /etc/logrotate.d/gradido.conf # create db user export DB_USER=gradido # create a new password only if it not already exist : "${DB_PASSWORD:=$(tr -dc '_A-Za-z0-9' < /dev/urandom | head -c 32)}" # Check if DB_PASSWORD is still empty, then exit with an error if [ -z "${DB_PASSWORD}" ]; then echo "Error: Failed to generate DB_PASSWORD." exit 1 fi export DB_PASSWORD mysql < $PROJECT_ROOT/database/.env # Configure backend export JWT_SECRET=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c 32; echo); envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env # Configure frontend envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env # Configure admin envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env # Configure dht-node export FEDERATION_DHT_SEED=$(< /dev/urandom tr -dc a-f0-9 | head -c 32; echo); envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env # Configure federation envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env # set all created or modified files back to belonging to gradido chown -R gradido:gradido $PROJECT_ROOT # create cronjob to delete yarn output in /tmp and for making backups regulary sudo -u gradido crontab < $LOCAL_SCRIPT_DIR/crontabs.txt # Start gradido sudo -u gradido $SCRIPT_PATH/start.sh $1