From 5bf3bf34a969b4332a02c35bea4aea75d88eb8d1 Mon Sep 17 00:00:00 2001 From: Valentin Date: Fri, 3 May 2024 19:09:09 +0200 Subject: [PATCH] first commit --- README.md | 80 +++++++++++++++++++++++++ assets/webhook.php | 70 ++++++++++++++++++++++ assets/webhook.sh | 19 ++++++ bin/create_user.sh | 23 ++++++++ bin/functions.sh | 27 +++++++++ bin/import_directus_db.sh | 38 ++++++++++++ bin/import_directus_schema.sh | 17 ++++++ bin/install_caddy.sh | 19 ++++++ bin/install_directus.sh | 46 +++++++++++++++ bin/install_mariadb.sh | 40 +++++++++++++ bin/install_node.sh | 22 +++++++ bin/install_nuxt_front.sh | 50 ++++++++++++++++ bin/set_url.sh | 20 +++++++ bin/setup_directus.sh | 60 +++++++++++++++++++ bin/setup_directus_db.sh | 35 +++++++++++ bin/setup_firewall_fail2ban.sh | 15 +++++ bin/setup_ssh.sh | 15 +++++ bin/setup_webhook.sh | 42 ++++++++++++++ bin/variables.sh | 19 ++++++ install.sh | 103 +++++++++++++++++++++++++++++++++ utils/export-content.sh | 39 +++++++++++++ utils/upgrade.sh | 1 + 22 files changed, 800 insertions(+) create mode 100644 README.md create mode 100644 assets/webhook.php create mode 100644 assets/webhook.sh create mode 100644 bin/create_user.sh create mode 100644 bin/functions.sh create mode 100644 bin/import_directus_db.sh create mode 100644 bin/import_directus_schema.sh create mode 100644 bin/install_caddy.sh create mode 100644 bin/install_directus.sh create mode 100644 bin/install_mariadb.sh create mode 100644 bin/install_node.sh create mode 100644 bin/install_nuxt_front.sh create mode 100644 bin/set_url.sh create mode 100644 bin/setup_directus.sh create mode 100644 bin/setup_directus_db.sh create mode 100644 bin/setup_firewall_fail2ban.sh create mode 100644 bin/setup_ssh.sh create mode 100644 bin/setup_webhook.sh create mode 100644 bin/variables.sh create mode 100644 install.sh create mode 100644 utils/export-content.sh create mode 100644 utils/upgrade.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..528c339 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# Deployment DCDN Static + +Deployment [**D**ebian](https://www.debian.org/) (os) + [**C**addy](https://caddyserver.com/) (webserver) + [**D**irectus](https://directus.io/) (cms) + [**N**uxt](https://nuxt.com/) (static front). + +## Installation + +On a fresh install as root user using + +`sudo passwd root` + +`su - root` + +1. Upgrade + +`apt update && apt upgrade -y` + +2. Install git + +`apt install -y git` + +3. Download and make the instal script executable + +`git clone https://figureslibres.io/gitea/valentin_le_moign/deployment-dcdn.git` + +`cd deployment-dcdn` + +`chmod u+x install.sh` + +4. Launch the script + +`bash install.sh` + +## Installation steps + +1. Install php for the webhook +2. Create a user +3. Setup ssh, firewall and fail2ban +4. Install Caddy webserver +5. Install MariaDB +6. Setup the Directus Database +7. Install Node +8. Prompt for the url +9. Install and run Directus +10. Install and run the front-end +11. Setup a webhook + +## Post-install + +0. Delete unix Debian account + +`userdel --remove-home debian` + +1. Configure DNS Zone +``` +Domain : | Type : A | Target : +Domain : cms. | Type : A | Target : +Domain : www. | Type : A | Target : +``` + + +2. Set Directus roles +``` +Website role Read content collections and directus_files +User role All permissions on content collections, directus_files and directus_folders +``` + + +3. Create a webhook +`/settings/hooks/gitea/new` +``` +Target URL https:///webhook.php +Branch filter prod +Authorization Header generate a safe string using : openssl rand -base64 32 +``` + +## Ref + +[Debian Web Server](https://figureslibres.io/gogs/bachir/debian-web-server) + +[Securing a dedicated server](https://help.ovhcloud.com/csm/en-gb-dedicated-servers-securing-server?id=kb_article_view&sysparm_article=KB0043969) diff --git a/assets/webhook.php b/assets/webhook.php new file mode 100644 index 0000000..04e9b18 --- /dev/null +++ b/assets/webhook.php @@ -0,0 +1,70 @@ + 10) { + $files = scandir($log_directory); + $log_files = array_diff($files, array('.', '..')); + usort($files, function($a, $b) use ($log_directory) { + return filemtime("$log_directory/$a") - filemtime("$log_directory/$b"); + }); + for ($i = 0; $i < 5; $i++) { + unlink("$log_directory/{$files[$i]}"); + } +} + +if (isset($decoded['repository'])) { + // git hook + echo shell_exec('bash ../webhook/webhook.sh ' . 'git' . ' >> ' . $log_directory . '/webhook_' . $current_date . '.log 2>&1'); +} else { + // directus hook + $debounce_delay = 1 * 60; + file_put_contents("debounce_hook", time()); + sleep($debounce_delay); + + if (time() >= intval(file_get_contents('debounce_hook')) + $debounce_delay) { + + echo shell_exec('bash ../webhook/webhook.sh ' . 'directus' . ' >> ' . $log_directory . '/webhook_' . $current_date . '.log 2>&1'); + } +} +?> diff --git a/assets/webhook.sh b/assets/webhook.sh new file mode 100644 index 0000000..c216d4b --- /dev/null +++ b/assets/webhook.sh @@ -0,0 +1,19 @@ +#!/bin/bash +hook_origin=$1 +repo_name=$(ls /var/www/repositories/ | grep -v '^cms') + +cd /var/www/repositories/$repo_name + +echo "Trigger : ${hook_origin}" + +if [[ "$hook_origin" == "git" ]]; then + git pull origin prod +fi + +jq '.scripts |= with_entries(.value |= gsub("\\bnuxt \\b"; "./node_modules/nuxt/bin/nuxt.mjs "))' package.json > temp.json && mv temp.json package.json + +node --max-old-space-size=250 `which npm` install -y +node --max-old-space-size=250 `which npm` run generate --prerender + +rm -r /var/www/html/public +cp -r "/var/www/repositories/${repo_name}/.output/public" /var/www/html \ No newline at end of file diff --git a/bin/create_user.sh b/bin/create_user.sh new file mode 100644 index 0000000..92a8501 --- /dev/null +++ b/bin/create_user.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +. bin/variables.sh + +echo -e "${PURPLE}${BOLD}Create user${RESET}" + +read -p "Enter username: " username + +if id "$username" &>/dev/null; then + echo "User '$username' already exists." + exit 1 +fi + +echo -e "${ORANGE}${BOLD}Generate and store the password somewhere safe${RESET}" +read -s -p "Enter password: " password +echo +useradd -m "$username" +chsh -s /bin/bash $username +echo "$username:$password" | chpasswd + +usermod -aG sudo $username + +echo -e "${PURPLE}${BOLD}User '$username' created with password successfully.${RESET}" \ No newline at end of file diff --git a/bin/functions.sh b/bin/functions.sh new file mode 100644 index 0000000..d16ef0c --- /dev/null +++ b/bin/functions.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +install_pkg() { + pkg="$1" + if ! dpkg -s "$pkg" >/dev/null 2>&1; then + apt update && apt install -y "$pkg" + echo -e "${PURPLE}${BOLD}${pkg} installed${RESET}" + fi +} + +get_username() { + if [[ -z "$username" ]]; then + username=$(getent passwd 1001 | cut -d: -f1) + fi +} + +get_ip() { + if [[ -z "$ip" ]]; then + ip=$(hostname -I | cut -d' ' -f1) + fi +} + +get_ssh_port() { + if [[ -z "$ssh_port" ]]; then + ssh_port=$(cat /etc/ssh/sshd_config.d/custom.conf | grep "Port " | sed 's/^Port //') + fi +} \ No newline at end of file diff --git a/bin/import_directus_db.sh b/bin/import_directus_db.sh new file mode 100644 index 0000000..fc87f97 --- /dev/null +++ b/bin/import_directus_db.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +get_ssh_port +get_username +get_ip + +echo -e "${PURPLE}${BOLD}Import the .tar.gz archive from your local storage${RESET}" +echo -e "${PURPLE}The archive should contain the sql dump, the upload directory and the .env file${RESET}" +echo -e "${BLUE}scp -P ${ssh_port} /local/path/to/archive.tar.gz ${username}@${ip}:/home/${username}/${RESET}" +echo -e "${PURPLE}${BOLD}Press any key when done${RESET}" +read + +directus_archive=$(ls /home/${username}/*.tar.gz); + +tar -xzf "${directus_archive}" -C "${CMS_DIRECTORY}" --strip-components=2 +rm "${directus_archive}" + +sed -i "s/^\(DB_PASSWORD=\)'.*'$/\1'$DB_DIRECTUS_PASSWORD'/" "${CMS_DIRECTORY}/.env" + +port=$(cat ${CMS_DIRECTORY}/.env | grep "^PORT=" | sed 's/^PORT=//') +sql_dump=$(ls ${CMS_DIRECTORY}/*.sql) + +install_pkg expect +mariadb -u directus -p"$DB_DIRECTUS_PASSWORD" directus < "$sql_dump" +rm $sql_dump +chown -R www-data:www-data $CMS_DIRECTORY + +su -s /bin/bash -c "cd ${CMS_DIRECTORY} &&\ + npm init -y &&\ + npx directus bootstrap --skipAdminInit &&\ + npx directus database migrate:latest + tmux new-session -d -s directus &&\ + tmux send-keys -t directus \"cd ${CMS_DIRECTORY} && npx directus start\" C-m" www-data + +echo -e "${PURPLE}Directus launched with imported database${RESET}" diff --git a/bin/import_directus_schema.sh b/bin/import_directus_schema.sh new file mode 100644 index 0000000..e10bafe --- /dev/null +++ b/bin/import_directus_schema.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +get_username +get_ip +get_ssh_port + +echo -e "${PURPLE}${BOLD}Import local Directus data model${RESET}" +echo -e "${BLUE}npx directus schema snapshot ./snapshot.yaml${RESET}" +echo -e "${BLUE}scp -P ${ssh_port} /local/path/to/snapshot.yaml ${username}@${ip}:/home/${username}/snapshot.yaml${RESET}" +echo -e "${PURPLE}${BOLD}Press any key when done${RESET}" +read + +su -s /bin/bash -c "cd ${CMS_DIRECTORY} &&\ +npx directus schema apply --yes /home/${username}/snapshot.yaml" www-data \ No newline at end of file diff --git a/bin/install_caddy.sh b/bin/install_caddy.sh new file mode 100644 index 0000000..ea2c1df --- /dev/null +++ b/bin/install_caddy.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +if systemctl is-enabled apache2 >/dev/null 2>&1; then + systemctl disable --now apache2 +fi + +install_pkg debian-keyring +install_pkg debian-archive-keyring +install_pkg apt-transport-https +install_pkg curl +curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg +curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list +install_pkg caddy +> /etc/caddy/Caddyfile + +echo -e "${PURPLE}${BOLD}Caddy Webserver installed${RESET}" \ No newline at end of file diff --git a/bin/install_directus.sh b/bin/install_directus.sh new file mode 100644 index 0000000..37de007 --- /dev/null +++ b/bin/install_directus.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +install_pkg tmux + +if [[ -z "$DB_DIRECTUS_PASSWORD" ]]; then + echo -e "${PURPLE}${BOLD}Enter the MariaDB Directus password : ${RESET}" + read -s DB_DIRECTUS_PASSWORD + echo +fi + +if [[ -z "$CMS_DIRECTORY" ]]; then + . bin/set_url.sh +fi + +echo "set -g default-shell /bin/sh" >> /etc/tmux.conf +su -s /bin/bash -c "mkdir ${CMS_DIRECTORY}" www-data + +echo -e "${PURPLE}${BOLD}Import the Directus database ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/import_directus_db.sh +else + . bin/setup_directus.sh + + echo -e "${PURPLE}${BOLD}Import Directus data model ? (y/N) ${RESET}" + read answer + if [[ "$answer" == "y" ]]; then + . bin/import_directus_schema.sh + fi + + echo -e "${PURPLE}${BOLD}You can now add some content${RESET}" + echo -e "${ORANGE}${BOLD}Do not forget to set the permissions${RESET}" + echo -e "${ORANGE}${BOLD}Website role ${RESET}${ORANGE}Read content collections and directus_files${RESET}" + echo -e "${ORANGE}${BOLD}User role ${RESET}${ORANGE}All permissions on content collections, directus_files and directus_folders${RESET}" +fi + +echo "cms.${DOMAIN_NAME} {" >> $CADDYFILE +echo "reverse_proxy ${ip}:${port}" >> $CADDYFILE +echo "}" >> $CADDYFILE +caddy fmt $CADDYFILE -w +caddy reload -c $CADDYFILE + +echo -e "${PURPLE}${BOLD}Access Directus ${RESET}${PURPLE}https://cms.${DOMAIN_NAME}${RESET}" diff --git a/bin/install_mariadb.sh b/bin/install_mariadb.sh new file mode 100644 index 0000000..9b11d92 --- /dev/null +++ b/bin/install_mariadb.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Automate mysql secure installation for debian-based systems +# https://gist.github.com/coderua/5592d95970038944d099 + +. bin/variables.sh +. bin/functions.sh + +install_pkg mariadb-server +echo -e "${ORANGE}${BOLD}Generate and store the password somewhere safe${RESET}" +echo -e "${PURPLE}${BOLD}Enter the MariaDB root password : ${RESET}" +read -s DB_ROOT_PASSWORD +echo +install_pkg expect +secure_mysql=$(expect -c " + set timeout 3 + spawn mysql_secure_installation + expect \"Enter current password for root (enter for none):\" + send \"\r\" + expect \"Switch to unix_socket authentication \\[Y/n\\]\" + send \"n\r\" + expect \"Change the root password? \\[Y/n\\]\" + send \"y\r\" + expect \"New password:\" + send \"$DB_ROOT_PASSWORD\r\" + expect \"Re-enter new password:\" + send \"$DB_ROOT_PASSWORD\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}" + +echo -e "${PURPLE}MariaDB is installed and secure${RESET}" diff --git a/bin/install_node.sh b/bin/install_node.sh new file mode 100644 index 0000000..7a5b033 --- /dev/null +++ b/bin/install_node.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +touch /var/www/.bashrc +mkdir /var/www/.nvm +mkdir /var/www/.npm +chown -R www-data:www-data /var/www + +install_pkg build-essential + +su -s /bin/bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash &&\ +export NVM_DIR="$HOME/.nvm" &&\ +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" &&\ +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" &&\ +nvm install v18' www-data +ln -sf /var/www/.nvm/versions/node/v18.*/bin/node /usr/bin/node +ln -sf /var/www/.nvm/versions/node/v18.*/bin/npm /usr/bin/npm +ln -sf /var/www/.nvm/versions/node/v18.*/bin/npx /usr/bin/npx + +echo -e "${PURPLE}Node installed${RESET}"; \ No newline at end of file diff --git a/bin/install_nuxt_front.sh b/bin/install_nuxt_front.sh new file mode 100644 index 0000000..355a2a0 --- /dev/null +++ b/bin/install_nuxt_front.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +get_ip + +echo -e "${PURPLE}${BOLD}Create and push a prod branch on the repo${RESET}" +echo -e "${BLUE}git fetch . main:prod${RESET}" +echo -e "${BLUE}git push origin prod${RESET}" +echo -e "${PURPLE}${BOLD}Enter the .git url of the repo${RESET}" +read repo_url + +front_repo_name=$(echo "$repo_url" | sed 's#.*/\([^/]*\)\.git#\1#') +front_directory="${REPO_DIRECTORY}/${front_repo_name}" +if [[ -z "$WEBSITE_TOKEN" ]]; then + echo -e "${PURPLE}${BOLD}Enter the Directus Website user static token${RESET}" + read -s WEBSITE_TOKEN +fi + +touch /var/www/.nuxtrc +echo "telemetry.consent=0" > /var/www/.nuxtrc +echo "telemetry.enabled=false" >> /var/www/.nuxtrc +chown -R www-data:www-data /var/www/.nuxtrc + +rm /var/www/html/* +chown www-data:www-data /var/www/html + +su -s /bin/bash -c "cd ${REPO_DIRECTORY} &&\ +git clone ${repo_url} &&\ +cd ${front_directory} &&\ +git checkout prod &&\ +echo \"DIRECTUS_API_TOKEN=${WEBSITE_TOKEN}\" > .env &&\ +echo \"URL=https://${DOMAIN_NAME}\" >> .env &&\ +echo \"DIRECTUS_URL=https://cms.${DOMAIN_NAME}\" >> .env &&\ +node --max-old-space-size=250 `which npm` install -y &&\ +node --max-old-space-size=250 `which npm` run generate --prerender" www-data + +cp -r "${front_directory}/.output/public" /var/www/html +chown -R www-data:www-data /var/www/html/public + +echo "www.${DOMAIN_NAME} {" >> $CADDYFILE +echo "redir ${DOMAIN_NAME}{uri} permanent" >> $CADDYFILE +echo "}" >> $CADDYFILE +echo "${DOMAIN_NAME} {" >> $CADDYFILE +echo "root * /var/www/html/public" >> $CADDYFILE +echo "file_server" >> $CADDYFILE +echo "}" >> $CADDYFILE +caddy fmt $CADDYFILE -w +caddy reload -c $CADDYFILE \ No newline at end of file diff --git a/bin/set_url.sh b/bin/set_url.sh new file mode 100644 index 0000000..5eb97d6 --- /dev/null +++ b/bin/set_url.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +echo -e "${PURPLE}${BOLD}Enter the domain name of the website${RESET}" +read DOMAIN_NAME +get_ip + +echo -e "${PURPLE}${BOLD}Configure the ${DOMAIN_NAME} DNS ZONE as the following${RESET}" +echo -e "${BLUE}Domain : ${DOMAIN_NAME} | Type : A | Target : ${ip}${RESET}" +echo -e "${BLUE}Domain : cms.${DOMAIN_NAME} | Type : A | Target : ${ip}${RESET}" +echo -e "${BLUE}Domain : www.${DOMAIN_NAME} | Type : A | Target : ${ip}${RESET}" +echo -e "${PURPLE}${BOLD}Press any key when done${RESET}" +read + +REPO_DIRECTORY="/var/www/repositories" +mkdir $repo_directory +chown www-data:www-data $repo_directory +CMS_DIRECTORY="${repo_directory}/cms_${DOMAIN_NAME}" diff --git a/bin/setup_directus.sh b/bin/setup_directus.sh new file mode 100644 index 0000000..1ef279f --- /dev/null +++ b/bin/setup_directus.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +echo -e "${ORANGE}${BOLD}Generate and store the credentials somewhere safe${RESET}" +echo -e "${PURPLE}${BOLD}Enter the Directus admin email : ${RESET}" +read directus_admin_email +echo -e "${PURPLE}${BOLD}Enter the Directus admin password : ${RESET}" +read -s directus_admin_password + +env_file="${CMS_DIRECTORY}/.env" +port=8055 + +key=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') +secret=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') + +su -s /bin/bash -c "mkdir ${CMS_DIRECTORY} &&\ +mkdir ${CMS_DIRECTORY}/uploads &&\ +echo \"HOST='${ip}'\" >> ${env_file} &&\ +echo \"PORT=${port}\" >> ${env_file} &&\ +echo \"PUBLIC_URL='https://cms.${DOMAIN_NAME}'\" >> ${env_file} &&\ +echo \"DB_CLIENT='mysql'\" >> ${env_file} &&\ +echo \"DB_HOST='127.0.0.1'\" >> ${env_file} &&\ +echo \"DB_PORT='3306'\" >> ${env_file} &&\ +echo \"DB_DATABASE='directus'\" >> ${env_file} &&\ +echo \"DB_USER='directus'\" >> ${env_file} &&\ +echo \"DB_PASSWORD='${DB_DIRECTUS_PASSWORD}'\" >> ${env_file} &&\ +echo \"SECRET='${secret}'\" >> ${env_file} &&\ +echo \"KEY='${key}'\" >> ${env_file} &&\ +echo \"CORS_ENABLED='true'\" >> ${env_file} &&\ +echo \"CORS_ORIGIN='true'\" >> ${env_file} &&\ +echo \"IMPORT_IP_DENY_LIST=\" >> ${env_file} &&\ +cd ${CMS_DIRECTORY} &&\ +npm init -y &&\ +npx directus bootstrap --skipAdminInit &&\ +tmux new-session -d -s directus &&\ +tmux send-keys -t directus \"cd ${CMS_DIRECTORY} && npx directus start\" C-m &&\ +npx directus roles create --role Administrator --admin true &&\ +npx directus roles create --role Website &&\ +npx directus roles create --role User" www-data + +admin_role_uuid=$(echo $(mariadb -u directus -p${DB_DIRECTUS_PASSWORD} \ +-e "SELECT id FROM directus.directus_roles WHERE name='Administrator'") | awk '{print $2}') +website_role_uuid=$(echo $(mariadb -u directus -p${DB_DIRECTUS_PASSWORD} \ +-e "SELECT id FROM directus.directus_roles WHERE name='Website'") | awk '{print $2}') +user_role_uuid=$(echo $(mariadb -u directus -p${DB_DIRECTUS_PASSWORD} \ +-e "SELECT id FROM directus.directus_roles WHERE name='User'") | awk '{print $2}') + +website_password=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') + +su -s /bin/bash -c "cd ${CMS_DIRECTORY} &&\ +npx directus users create --email \"${directus_admin_email}\" \ +--password \"${directus_admin_password}\" --role \"${admin_role_uuid}\" &&\ +npx directus users create --email \"website@${DOMAIN_NAME}\" --password \"${website_password}\" --role \"${website_role_uuid}\"" www-data + +WEBSITE_TOKEN=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') +mariadb -u directus -p${DB_DIRECTUS_PASSWORD} -e "UPDATE directus.directus_roles SET icon='robot' WHERE name='Website'"; +mariadb -u directus -p${DB_DIRECTUS_PASSWORD} -e "UPDATE directus.directus_roles SET app_access='0' WHERE name='Website'"; +mariadb -u directus -p${DB_DIRECTUS_PASSWORD} -e "UPDATE directus.directus_users SET token=\"${WEBSITE_TOKEN}\" WHERE email=\"website@${DOMAIN_NAME}\""; \ No newline at end of file diff --git a/bin/setup_directus_db.sh b/bin/setup_directus_db.sh new file mode 100644 index 0000000..678355f --- /dev/null +++ b/bin/setup_directus_db.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +if ! dpkg -s mariadb-server >/dev/null 2>&1; then + . bin/install_mariadb.sh +fi + +echo -e "${ORANGE}${BOLD}Generate and store the password somewhere safe${RESET}" +echo -e "${PURPLE}${BOLD}Enter the MariaDB Directus password : ${RESET}" +read -s DB_DIRECTUS_PASSWORD +echo +if [[ -z "$DB_ROOT_PASSWORD" ]]; then + echo -e "${PURPLE}${BOLD}Enter the MariaDB root password : ${RESET}" + read -s DB_ROOT_PASSWORD + echo +fi +install_pkg expect +create_directus_db=$(expect -c " + spawn mariadb -u root -p + expect \"Enter password:\" + send \"$DB_ROOT_PASSWORD\r\" + expect \"mysql>\" + send \"CREATE USER 'directus'@'localhost' IDENTIFIED BY '${DB_DIRECTUS_PASSWORD}';\r\" + send \"CREATE DATABASE directus;\r\" + send \"GRANT ALL PRIVILEGES ON directus.* TO 'directus'@'localhost' IDENTIFIED BY '${DB_DIRECTUS_PASSWORD}';\r\" + send \"FLUSH PRIVILEGES;\r\" + expect \"mysql>\" + send \"quit;\r\" + expect eof +") +echo "${create_directus_db}" >& /dev/null + +echo -e "${PURPLE}Directus database created${RESET}" \ No newline at end of file diff --git a/bin/setup_firewall_fail2ban.sh b/bin/setup_firewall_fail2ban.sh new file mode 100644 index 0000000..6863f21 --- /dev/null +++ b/bin/setup_firewall_fail2ban.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +echo -e "${PURPLE}${BOLD}Setup Firewall and Fail2ban${RESET}" +install_pkg ufw +install_pkg fail2ban +systemctl enable fail2ban +get_ssh_port +ufw allow $ssh_port +ufw allow http +ufw allow https + +echo -e "${PURPLE}Firewall and Fail2ban are setup${RESET}" \ No newline at end of file diff --git a/bin/setup_ssh.sh b/bin/setup_ssh.sh new file mode 100644 index 0000000..cfdc1ab --- /dev/null +++ b/bin/setup_ssh.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +. bin/variables.sh + +echo -e "${PURPLE}${BOLD}Setup SSH${RESET}" + +ssh_port=$((RANDOM % (65536 - 1024 + 1) + 1024)) + +touch /etc/ssh/sshd_config.d/custom.conf +echo "PermitRootLogin no" >> /etc/ssh/sshd_config.d/custom.conf +echo "PermitEmptyPasswords no" >> /etc/ssh/sshd_config.d/custom.conf +echo "Port ${ssh_port}" >> /etc/ssh/sshd_config.d/custom.conf +systemctl reload ssh + +echo -e "${ORANGE}${BOLD}Store the ssh port ${ssh_port} somewhere safe${RESET}" \ No newline at end of file diff --git a/bin/setup_webhook.sh b/bin/setup_webhook.sh new file mode 100644 index 0000000..5417755 --- /dev/null +++ b/bin/setup_webhook.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +. bin/variables.sh +. bin/functions.sh + +echo -e "${PURPLE}${BOLD}If it does not already exists, create a webhook at the following url${RESET}" +echo -e "${PURPLE}${BOLD}${repo_url}/settings/hooks/gitea/new${RESET}" +echo -e "${BLUE}${BOLD}Target URL ${RESET}${BLUE}https://${domain_name}/webhook.php${RESET}" +echo -e "${BLUE}${BOLD}Branch filter ${RESET}${BLUE}prod${RESET}" +echo -e "${BLUE}${BOLD}Authorization Header ${RESET}${ORANGE}Generate a safe string using \`openssl rand -base64 32\`${RESET}" +echo -e "${PURPLE}${BOLD}Enter the Authorization Header${RESET}" +read -s auth_header + +install_pkg php +install_pkg php-fpm +install_pkg jq + +rm /var/www/html/index.html +cp ./assets/webhook.php /var/www/html/ +mkdir /var/www/webhook +cp ./assets/webhook.sh /var/www/webhook +chown www-data:www-data /var/www/webhook/webhook.sh +chmod u+x /var/www/webhook/webhook.sh +mkdir /var/www/webhook/logs +chown www-data:www-data /var/www/webhook/logs + +get_ip + +head -n $(($(wc -l < $CADDYFILE) - 2)) $CADDYFILE > temp_Caddyfile && mv temp_Caddyfile $CADDYFILE +echo "handle /webhook.php {" >> $CADDYFILE +echo "@unauthorized not header Authorization \"${auth_header}\"" >> $CADDYFILE +echo "respond @unauthorized \"Unauthorized access\"" >> $CADDYFILE +echo "root * /var/www/html" >> $CADDYFILE +echo "php_fastcgi unix//run/php/php8.2-fpm.sock" >> $CADDYFILE +echo "file_server" >> $CADDYFILE +echo "}" >> $CADDYFILE +echo "handle {" >> $CADDYFILE +echo "reverse_proxy ${ip}:3000" >> $CADDYFILE +echo "}" >> $CADDYFILE +echo "}" >> $CADDYFILE +caddy fmt $CADDYFILE -w +caddy reload -c $CADDYFILE \ No newline at end of file diff --git a/bin/variables.sh b/bin/variables.sh new file mode 100644 index 0000000..471b68b --- /dev/null +++ b/bin/variables.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Texts layout +PURPLE='\033[35m' +ORANGE='\033[33m' +BLUE='\033[34m' +BOLD='\033[1m' +RESET='\033[0m' + +DB_ROOT_PASSWORD="" +DB_DIRECTUS_PASSWORD="" + +DOMAIN_NAME="" +CMS_DIRECTORY="" +REPO_DIRECTORY="" + +WEBSITE_TOKEN="" + +CADDYFILE="/etc/caddy/Caddyfile" \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..29d892c --- /dev/null +++ b/install.sh @@ -0,0 +1,103 @@ +#!/bin/bash + + +# TODO +## DIRECTUS EMAIL +## DIRECTUS REDIS +## LOGING DE TOUT +## CADDYFILE EN JSON +## MÀJ +## reboot a running system +## MATOMO +## NODE EXPORTER + +. bin/functions.sh +. bin/variables.sh + +echo -e "${PURPLE}${BOLD}Deployment Debian + Caddy + Directus + Nuxt${RESET}" + +if [ "$EUID" -ne 0 ]; then + echo "Please run as root" + exit +fi + +if [ "$(dirname "$0")" != "$(pwd)" ]; then + echo "Please run this script from its directory." + exit +fi + +# USER +echo -e "${PURPLE}${BOLD}Create a user ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/create_user.sh +fi + +# SSH +echo -e "${PURPLE}${BOLD}Setup SSH ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/setup_ssh.sh +fi + +# FIREWALL AND FAIL2BAN +echo -e "${PURPLE}${BOLD}Setup Firewall and Fail2ban ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/setup_firewall_fail2ban.sh +fi + +# CADDY +echo -e "${PURPLE}${BOLD}Install Caddy webserver ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/install_caddy.sh +fi + +# MARIADB +echo -e "${PURPLE}${BOLD}Install MariaDB ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/install_mariadb.sh +fi + +# DIRECTUS DB +echo -e "${PURPLE}${BOLD}Setup Directus database ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/setup_directus_db.sh +fi + +# NODE +echo -e "${PURPLE}${BOLD}Install Node ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/install_node.sh +fi + +# SET URL +echo -e "${PURPLE}${BOLD}Set url ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/set_url.sh +fi + +# INSTALL DIRECTUS +echo -e "${PURPLE}${BOLD}Install Directus ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/install_directus.sh +fi + +# NUXT STATIC +echo -e "${PURPLE}${BOLD}Install the front-end ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + . bin/install_nuxt_front.sh + + echo -e "${PURPLE}${BOLD}Setup a webhook ? (y/N) ${RESET}" + read answer + if [[ "$answer" == "y" ]]; then + . bin/setup_webhook.sh + fi +fi \ No newline at end of file diff --git a/utils/export-content.sh b/utils/export-content.sh new file mode 100644 index 0000000..d505499 --- /dev/null +++ b/utils/export-content.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +if [ "$EUID" -ne 0 ]; then + echo "Please run as root" + exit +fi + +PURPLE='\033[35m' +BLUE='\033[34m' +BOLD='\033[1m' +RESET='\033[0m' + +echo -e "${PURPLE}${BOLD}Export Directus Database and files ? (y/N) ${RESET}" +read answer +if [[ "$answer" == "y" ]]; then + user=$(getent passwd 1001 | awk -F: '{print $1}') + + site_name=$(ls /var/www/repositories/ | grep -v '^cms') + db_password=$(cat /var/www/repositories/cms*/.env | grep DB_PASSWORD | sed "s/[^']*'\([^']*\)'.*/\1/") + current_date=$(date +'%d-%m-%y_%H-%M') + export_base_folder="/home/${user}/content_exports" + export_folder="${export_base_folder}/${site_name}_export_${current_date}" + + mkdir -p "${export_folder}" + mysqldump -u directus -p"${db_password}" directus > "${export_folder}/db_${site_name}_${current_date}.sql" + cp -r /var/www/repositories/cms*/uploads "${export_folder}" + cp -r /var/www/repositories/cms*/.env "${export_folder}" + tar -czf "${export_folder}.tar.gz" -C "${export_base_folder}" . + rm -r "${export_folder}" + chown -R "${user}:${user}" "${export_base_folder}" + + ssh_port=$(cat /etc/ssh/sshd_config.d/custom.conf | grep "Port " | sed 's/^Port //') + ip=$(hostname -I) + if [[ "${ip: -1}" == " " ]]; then + ip="${ip%?}" + fi + echo -e "${PURPLE}${BOLD}You can now download the backup${RESET}" + echo -e "${BLUE}scp -P ${ssh_port} ${user}@${ip}:${export_folder}.tar.gz ./path/to/local/folder${RESET}" +fi \ No newline at end of file diff --git a/utils/upgrade.sh b/utils/upgrade.sh new file mode 100644 index 0000000..cc1f786 --- /dev/null +++ b/utils/upgrade.sh @@ -0,0 +1 @@ +#!/bin/bash \ No newline at end of file