diff --git a/README.md b/README.md index 8d3eae6..460faed 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -Deployment [**D**ebian](https://www.debian.org/) (os) + [**D**ocker](https://www.docker.com/) (containerization) + [**C**addy](https://caddyserver.com/) (webserver) + [**D**irectus](https://directus.io/) (cms) + [**N**uxt](https://nuxt.com/) (static front). +# DeployDeck + +Deployment [Debian](https://www.debian.org/) (os) + [Docker](https://www.docker.com/) (containerization) + [Caddy](https://caddyserver.com/) (webserver) + [Directus](https://directus.io/) (cms) + [Nuxt](https://nuxt.com/) (static front). ## Installation @@ -14,9 +16,10 @@ Upgrade ## TODO -Staging server with password -Email server -Detect if first installlation -Directus Redis -Password database -Remove a website \ No newline at end of file +- Add site as non root user +- Staging server with password +- Email server +- Detect if first installlation +- Password database +- Remove a website +- Administration pannel \ No newline at end of file diff --git a/assets/setup_mariadb.sql b/assets/setup_mariadb.sql deleted file mode 100644 index 564217b..0000000 --- a/assets/setup_mariadb.sql +++ /dev/null @@ -1,3 +0,0 @@ -CREATE DATABASE IF NOT EXISTS directus; - -GRANT ALL PRIVILEGES ON directus.* TO 'root'@'%'; \ No newline at end of file diff --git a/bin/add-site/install_directus.sh b/bin/add-site/install_directus.sh index d35760d..5fb49e8 100644 --- a/bin/add-site/install_directus.sh +++ b/bin/add-site/install_directus.sh @@ -4,102 +4,139 @@ check_global_const DOMAIN_NAME USERNAME CADDYFILE IP SSH_PORT mkdir "/home/${USERNAME}/cms.${DOMAIN_NAME}" cp assets/directus.docker-compose.yml "/home/${USERNAME}/cms.${DOMAIN_NAME}/docker-compose.yml" -cp assets/setup_mariadb.sql "/home/${USERNAME}/cms.${DOMAIN_NAME}/setup_mariadb.sql" cp assets/.env.example "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" sed -i "s/^PROJECT_NAME=.*/PROJECT_NAME=${DOMAIN_NAME}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" -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 +set_admin_credentials() { + 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 -sed -i "s/^ADMIN_EMAIL=.*/ADMIN_EMAIL=${directus_admin_email}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" -sed -i "s/^ADMIN_PASSWORD=.*/ADMIN_PASSWORD=${directus_admin_password}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" + sed -i "s/^ADMIN_EMAIL=.*/ADMIN_EMAIL=${directus_admin_email}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" + sed -i "s/^ADMIN_PASSWORD=.*/ADMIN_PASSWORD=${directus_admin_password}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" +} -# @TODO: random port +set_port() { + # @TODO: random port + # @TODO: check if port is available + port=8055 + sed -i "s/^PORT=.*/PORT=${port}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" +} -port=8055 +set_secrets() { + key=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') + secret=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') + sed -i "s/^KEY=.*/KEY=${key}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" + sed -i "s/^SECRET=.*/SECRET=${secret}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" +} -key=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') -secret=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') +wait_for_DB() { + echo "Waiting for Directus database to be ready..." + until docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -uroot -e "SELECT 1 FROM directus.directus_roles LIMIT 1" &> /dev/null + do + echo "Database not ready yet... waiting 5 seconds" + sleep 5 + done +} -sed -i "s/^KEY=.*/KEY=${key}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" -sed -i "s/^SECRET=.*/SECRET=${secret}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" -sed -i "s/^PORT=.*/PORT=${port}/" "/home/${USERNAME}/cms.${DOMAIN_NAME}/.env" - -docker compose -f "/home/${USERNAME}/cms.${DOMAIN_NAME}/docker-compose.yml" up -d - -docker exec -i "${DOMAIN_NAME}_Directus" sh -c "npx directus bootstrap" - -echo "Waiting for Directus database to be ready..." -until docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -uroot -e "SELECT 1 FROM directus.directus_roles LIMIT 1" &> /dev/null -do - echo "Database not ready yet... waiting 5 seconds" - sleep 5 -done - -# @TODO: ask if import db -# and prompt "take care of permissions settings" -# else do the install db manipulations - -docker cp assets/directus_policies.sql "${DOMAIN_NAME}_Directus_DB:/directus_policies.sql" -docker exec -i "${DOMAIN_NAME}_Directus_DB" sh -c " - mariadb -uroot directus < /directus_policies.sql -" - -website_role_uuid=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_roles WHERE name='Website'") -user_role_uuid=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_roles WHERE name='User'") -admin_role_uuid=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_roles WHERE name='Administrator'") - -website_password=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') - -docker exec -i "${DOMAIN_NAME}_Directus" sh -c "npx directus users create --email \"website@${DOMAIN_NAME}\" --password \"${website_password}\" --role \"${website_role_uuid}\"" - -WEBSITE_TOKEN=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') - -docker exec -i "${DOMAIN_NAME}_Directus_DB" sh -c " - mariadb -uroot -e \" - UPDATE directus.directus_users SET role='${admin_role_uuid}' WHERE first_name='Admin'; - UPDATE directus.directus_users SET token='${WEBSITE_TOKEN}' WHERE email='website@${DOMAIN_NAME}'; - \" directus -" - -docker network connect web "${DOMAIN_NAME}_Directus" - -echo -e "${PURPLE}${BOLD}Import Directus data model ? (y/N) ${RESET}" +echo -e "${PURPLE}${BOLD}Import the Directus database ? (y/N) ${RESET}" read answer if [[ "$answer" == "y" ]]; then - echo -e "${PURPLE}${BOLD}Make sure your local Directus is the latest version${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}" +# @TODO: finish import db +# fix where everything is set (admin not for db import, network connect for both...) +# do we really need the .env file ? + set_port + set_secrets + docker-compose -f "/home/${USERNAME}/cms.${DOMAIN_NAME}/docker-compose.yml" up -d + docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -uroot -e "CREATE DATABASE directus; GRANT ALL PRIVILEGES ON directus.* TO 'root'@'%';" + wait_for_DBthe directus user + + echo -e "${PURPLE}${BOLD}Import the .tar.gz archive from your local storage${RESET}" + echo -e "${PURPLE}The archive should contain the sql dump and the upload directory${RESET}" + echo -e "${PURPLE}Make sure the Website Directus user permissions are setup${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 - docker cp /home/${USERNAME}/snapshot.yaml "${DOMAIN_NAME}_Directus":/directus/snapshot.yaml - docker exec -i "${DOMAIN_NAME}_Directus" sh -c "npx directus schema apply --yes ./snapshot.yaml" + directus_archive=$(ls /home/${USERNAME}/*.tar.gz); + tar -xzf "${directus_archive}" -C "/home/${USERNAME}/cms.${DOMAIN_NAME}" --strip-components=2 + rm "${directus_archive}" + sql_dump=$(ls /home/${USERNAME}/cms.${DOMAIN_NAME}/*.sql) + docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -uroot directus < "${sql_dump}" - can_see_policy_id=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_policies WHERE name='CanSee'") - can_edit_policy_id=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_policies WHERE name='CanEdit'") + docker exec -i "${DOMAIN_NAME}_Directus" sh -c " + npx directus bootstrap --skipAdminInit &&\ + npx directus database migrate:latest + " +else + set_admin_credentials + set_port + set_secrets + docker compose -f "/home/${USERNAME}/cms.${DOMAIN_NAME}/docker-compose.yml" up -d + docker exec -i "${DOMAIN_NAME}_Directus" sh -c "npx directus bootstrap" + wait_for_DB - collections=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" sh -c "mariadb -N -u root directus -e \"SELECT collection FROM directus_collections;\"" | tr -d '\r') - for collection_name in $collections; do - echo $collection_name - docker exec -i "${DOMAIN_NAME}_Directus_DB" sh -c " - mariadb -uroot directus -e \" - INSERT INTO directus_permissions (collection, action, permissions, fields, policy) - VALUES - ('${collection_name}', 'read', '{}', '*', '${can_see_policy_id}'), - ('${collection_name}', 'read', '{}', '*', '${can_edit_policy_id}'), - ('${collection_name}', 'create', '{}', '*', '${can_edit_policy_id}'), - ('${collection_name}', 'update', '{}', '*', '${can_edit_policy_id}'), - ('${collection_name}', 'delete', '{}', '*', '${can_edit_policy_id}'); - \" - " - done + docker cp assets/directus_policies.sql "${DOMAIN_NAME}_Directus_DB:/directus_policies.sql" + docker exec -i "${DOMAIN_NAME}_Directus_DB" sh -c " + mariadb -uroot directus < /directus_policies.sql + " + + website_role_uuid=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_roles WHERE name='Website'") + user_role_uuid=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_roles WHERE name='User'") + admin_role_uuid=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_roles WHERE name='Administrator'") + + website_password=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') + + docker exec -i "${DOMAIN_NAME}_Directus" sh -c "npx directus users create --email \"website@${DOMAIN_NAME}\" --password \"${website_password}\" --role \"${website_role_uuid}\"" + + WEBSITE_TOKEN=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') + + docker exec -i "${DOMAIN_NAME}_Directus_DB" sh -c " + mariadb -uroot -e \" + UPDATE directus.directus_users SET role='${admin_role_uuid}' WHERE first_name='Admin'; + UPDATE directus.directus_users SET token='${WEBSITE_TOKEN}' WHERE email='website@${DOMAIN_NAME}'; + \" directus + " + # @TODO: Create the upload directory or make sure it is writable + + echo -e "${PURPLE}${BOLD}Import Directus data model ? (y/N) ${RESET}" + read answer + if [[ "$answer" == "y" ]]; then + echo -e "${PURPLE}${BOLD}Make sure your local Directus is the latest version${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 + + docker cp /home/${USERNAME}/snapshot.yaml "${DOMAIN_NAME}_Directus":/directus/snapshot.yaml + docker exec -i "${DOMAIN_NAME}_Directus" sh -c "npx directus schema apply --yes ./snapshot.yaml" + + can_see_policy_id=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_policies WHERE name='CanSee'") + can_edit_policy_id=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" mariadb -N -uroot -e "SELECT id FROM directus.directus_policies WHERE name='CanEdit'") + + collections=$(docker exec -i "${DOMAIN_NAME}_Directus_DB" sh -c "mariadb -N -u root directus -e \"SELECT collection FROM directus_collections;\"" | tr -d '\r') + for collection_name in $collections; do + echo $collection_name + docker exec -i "${DOMAIN_NAME}_Directus_DB" sh -c " + mariadb -uroot directus -e \" + INSERT INTO directus_permissions (collection, action, permissions, fields, policy) + VALUES + ('${collection_name}', 'read', '{}', '*', '${can_see_policy_id}'), + ('${collection_name}', 'read', '{}', '*', '${can_edit_policy_id}'), + ('${collection_name}', 'create', '{}', '*', '${can_edit_policy_id}'), + ('${collection_name}', 'update', '{}', '*', '${can_edit_policy_id}'), + ('${collection_name}', 'delete', '{}', '*', '${can_edit_policy_id}'); + \" + " + done + fi fi +docker network connect web "${DOMAIN_NAME}_Directus" + if ! grep -q "cms.${DOMAIN_NAME}" "$CADDYFILE"; then echo "cms.${DOMAIN_NAME} {" >> "$CADDYFILE" echo " reverse_proxy ${DOMAIN_NAME}_Directus:${port}" >> "$CADDYFILE" @@ -109,3 +146,4 @@ if ! grep -q "cms.${DOMAIN_NAME}" "$CADDYFILE"; then else echo -e "${ORANGE}${BOLD}Entry for cms.${DOMAIN_NAME} already exists in $CADDYFILE.${RESET}" fi +sh -c \ No newline at end of file diff --git a/bin/first-install/setup_ssh.sh b/bin/first-install/setup_ssh.sh index ec1e744..c8ee3a1 100644 --- a/bin/first-install/setup_ssh.sh +++ b/bin/first-install/setup_ssh.sh @@ -8,6 +8,7 @@ read answer if [[ "$answer" == "y" ]]; then echo -e "${PURPLE}${BOLD}Enter the desired SSH port (between 1024 and 65535):${RESET}" read port + # @ TODO : is manually setting port really working ? if [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1024 ] && [ "$port" -le 65535 ]; then SSH_PORT=$port else