diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f09d69a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +# Utilise la même base que ton serveur Scaleway +FROM debian:12-slim + +# Évite les erreurs 'TERM environment variable not set' lors du 'clear' +ENV TERM=xterm +# Empêche les interfaces interactives pendant l'installation des paquets +ENV DEBIAN_FRONTEND=noninteractive + +# Installation des dépendances +# Note : on utilise docker.io pour avoir le binaire /usr/bin/docker +RUN apt-get update && apt-get install -y \ + curl \ + cron \ + sudo \ + procps \ + docker.io \ + docker-compose \ + && rm -rf /var/lib/apt/lists/* + +# Création de l'arborescence de travail +WORKDIR /app + +# On copie le contenu du projet +# Assure-toi d'être à la racine de 'serverconfig' quand tu buildes +COPY . . + +# On rend les scripts exécutables +# Utilisation de find pour être sûr de ne rater aucun script dans les sous-dossiers +RUN find . -name "*.sh" -exec chmod +x {} + + +# On lance le script d'installation +# Utilisation de la forme exec pour une meilleure gestion des signaux +CMD ["./install.sh"] diff --git a/scripts/disk-monitor.sh b/disk-monitor.sh similarity index 63% rename from scripts/disk-monitor.sh rename to disk-monitor.sh index 3d7ea84..1c6f493 100644 --- a/scripts/disk-monitor.sh +++ b/disk-monitor.sh @@ -1,32 +1,34 @@ #!/bin/bash -source /usr/local/bin/libs/common.sh -source /etc/serverconfig/.env +# DISK MONITORING & INSTALLATION SCRIPT +# This script monitors disk usage and sends notifications. +# It can also self-install into the system crontab. + +PROJECT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +readonly PROJECT_DIR 2>/dev/null + +source $PROJECT_DIR/utils.sh +source $ENV_FILE INSTALLED=$1 if [[ "--install" == $INSTALLED ]]; then - info_print "\n\ -==================================================\n\ - disk-monitor Installation\n\ ---------------------------------------------------" + log_info "disk-monitor Installation" + if ! command -v crontab >/dev/null 2>&1; then - info_print "Error: crontab not found." $ERROR_FLAG + log_error "Error: crontab not found." exit 1 fi - CRON_JOB="0 3 * * 1 $SCRIPT_FILE/scripts/disk-monitor.sh" + CRON_JOB="0 3 * * 1 $PROJECT_DIR/disk-monitor.sh" crontab -l | grep -F "$CRON_JOB" > /dev/null 2>&1 if ! crontab -l | grep -Fq "$CRON_JOB"; then (crontab -l 2>/dev/null; echo "$CRON_JOB") | crontab - - info_print "Cron job added." $SUCCESS_FLAG + log_success "Cron job added." fi exit 0; fi -source /usr/local/bin/libs/notifications.sh - usage=80 - send_notification "$( df -h / | grep / | awk -v max="$usage" '{ usage = $5; diff --git a/docker-compose.sh b/docker-compose.sh new file mode 100644 index 0000000..2c6a9df --- /dev/null +++ b/docker-compose.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +PROJECT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +readonly PROJECT_DIR 2>/dev/null + +source $PROJECT_DIR/utils.sh +source $ENV_FILE + +if [[ "--install" == $1 ]]; then + log_info "docker-compose Installation" + COMPOSE_FILE="$(realpath "$PROJECT_DIR/docker-compose.yml")" + + if [[ -f "$COMPOSE_FILE" ]]; then + docker compose -f "$COMPOSE_FILE" up -d --force-recreate --remove-orphans && \ + log_success "$COMPOSE_FILE is running."; + + else log_error "no docker-compose.yml found at $PROJECT_DIR"; + fi + exit 0; +fi \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 2017cf4..bb2d381 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -69,9 +69,9 @@ services: DOCKER_HOST: tcp://socket-rw:2375 # Uses RW proxy to pause containers during backup volumes: - wireguard-data:/backup/wireguard:ro - - ./synapse:/backup/synapse:ro + - ./data/synapse:/backup/synapse:ro - ssl-data:/backup/ssl:ro - - ./backup:/archive + - ./data/backup:/archive networks: - socket-rw-bridge - web-network @@ -89,8 +89,8 @@ services: - ENABLE_IPV6=true volumes: - ssl-data:/etc/nginx/certs:ro - - ./nginx/default_html:/usr/share/nginx/html - - ./nginx/vhost.d:/etc/nginx/vhost.d + - ./data/nginx/default_html:/usr/share/nginx/html + - ./data/nginx/vhost.d:/etc/nginx/vhost.d labels: - "docker-volume-backup.stop-during-backup=true" # Ensure consistency during backup depends_on: @@ -110,9 +110,9 @@ services: - DOCKER_HOST=tcp://socket-rw:2375 # Needs RW to restart Nginx after renewal volumes: - ssl-data:/etc/nginx/certs - - ./nginx/vhost.d:/etc/nginx/vhost.d - - ./nginx/default_html:/usr/share/nginx/html - - ./nginx/acme_config:/etc/acme.sh + - ./data/nginx/vhost.d:/etc/nginx/vhost.d + - ./data/nginx/default_html:/usr/share/nginx/html + - ./data/nginx/acme_config:/etc/acme.sh labels: - "docker-volume-backup.stop-during-backup=true" depends_on: @@ -132,7 +132,7 @@ services: # - LETSENCRYPT_HOST=${HOSTNAME}, www.${HOSTNAME} # - LETSENCRYPT_EMAIL=${EMAIL} # volumes: - # - ./data:/usr/share/nginx/html/data + # - /data/public:/usr/share/nginx/html/data # networks: # - web-network @@ -186,7 +186,7 @@ services: container_name: synapse restart: unless-stopped volumes: - - ./synapse:/data + - ./data/synapse:/data environment: - SYNAPSE_CONFIG_PATH=/data/homeserver.yaml - VIRTUAL_HOST=msg.${HOSTNAME} @@ -210,7 +210,7 @@ services: - GITEA__server__ROOT_URL=https://git.${HOSTNAME}/ - DISABLE_REGISTRATION=true # Private instance security volumes: - - ./gitea:/data + - ./data/gitea:/data - /etc/localtime:/etc/localtime:ro ports: - "222:22" # SSH port mapping for Git operations @@ -227,7 +227,7 @@ services: - LETSENCRYPT_HOST=mirror.${HOSTNAME} - LETSENCRYPT_EMAIL=${EMAIL} - VIRTUAL_PORT=4321 - - BETTER_AUTH_SECRET=${MIRROR_AUTH_SECRET} + - BETTER_AUTH_SECRET=${GITHUB_AUTH_SECRET} volumes: - gitea-mirror-data:/app/data networks: diff --git a/install.sh b/install.sh index 3267d34..1f9f0ed 100644 --- a/install.sh +++ b/install.sh @@ -1,32 +1,17 @@ #!/bin/bash -set -euo pipefail +PROJECT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +readonly PROJECT_DIR 2>/dev/null +source "$PROJECT_DIR/utils.sh" -readonly PROJECT_NAME="serverconfig" -readonly PROJECT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# set -euo pipefail -readonly REQ=("curl" "docker") - -readonly ENV_FILE="${PROJECT_DIR}/.env" - -readonly GREEN='\033[0;32m' -readonly RED='\033[0;31m' -readonly YELLOW='\033[1;33m' -readonly BLUE='\033[0;34m' -readonly NC='\033[0m' - -DATETIME_FORMAT="%d-%m-%Y %H:%M:%S" - -function log() { - local type="${1}" - local color="${2}" - local message="${3}" - echo -e "${color}[$(date +"$DATETIME_FORMAT")] [${type}]${NC} ${message}" -} - -function log_info() { log "INFO" "$BLUE" "$1"; } -function log_success() { log "OK " "$GREEN" "$1"; } -function log_error() { log "ERR " "$RED" "$1" >&2; } +ENV_LIST=( + "EMAIL" "HOSTNAME" + "TELEGRAM_TOKEN" "TELEGRAM_CHAT_ID" + "AWS" "ENDPOINT" "AWS_ACCESS_KEY_ID" "AWS_SECRET_ACCESS_KEY" + "GITHUB_AUTH_SECRET" +) function check_root() { if [[ $EUID -ne 0 ]]; then @@ -49,8 +34,13 @@ function check_dependencies() { function install_scripts() { log_info "Installing scripts..." - for script in "$SCRIPT_FILE"/*.sh; do + for script in "$PROJECT_DIR"/*.sh; do [ -e "$script" ] || continue + + if [[ "$script" == "$(realpath "$0")" ]]; then + continue + fi + log_info "Configuring $(basename "$script")..." if ! bash "$script" --install; then log_error "Hook failed for $script" @@ -68,9 +58,17 @@ function main() { log_info "Creating directories and files..." touch "$ENV_FILE" + for env in "${ENV_LIST[@]}"; do + read -sp "Enter value for $env: " value + echo + env_variable "$env" "$value" + done + install_scripts log_success "Installation Complete" } -main "$@" \ No newline at end of file +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi \ No newline at end of file diff --git a/libs/common.sh b/libs/common.sh deleted file mode 100644 index 13edb27..0000000 --- a/libs/common.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/bash - -FILENAME="serverconfig" - -ETC_DIR="/etc/$FILENAME" -ENV_FILE="$ETC_DIR/.env" -LOG="/var/log/$FILENAME.log" -SCRIPT_FILE="/usr/local/bin" - -INFO="\e[34mINFO\e[0m" -SUCCESS="\e[32mSUCCESS\e[0m" -WARN="\e[33mWARN\e[0m" -ERROR="\e[31mERROR\e[0m" -DEBUG="\e[35mDEBUG\e[0m" -ACTION="\e[36mACTION\e[0m" - -INFO_FLAG=1 -WARN_FLAG=2 -ERROR_FLAG=3 -DEBUG_FLAG=4 -ACTION_FLAG=5 -SUCCESS_FLAG=6 - - -DATETIME_FORMAT="%d-%m-%Y %H:%M:%S" - -info_print() { - local message="$1" - local level="${2:-1}" - local write_log="${3:-true}" - - case $level in - 1|--) local level=$INFO;; - 2) local level=$WARN;; - 3) local level=$ERROR;; - 4) local level=$DEBUG;; - 5) local level=$ACTION;; - 6) local level=$SUCCESS;; - *);; - esac - - local output="[$(date +"$DATETIME_FORMAT")] - $level: $message" - - if [ "$write_log" = true ]; then echo -e "$output" | tee -a "$LOG" - else echo -e "$output" - fi -} - -create_env_variable() { - local key="$1" - local value="$2" - local file="${3:-$ENV_FILE}" - local isUpdated="${4:-true}" - - if [[ "$file" == '--' ]]; then - file=$ENV_FILE - fi - - if [[ -z "$value" && "$isUpdated" == true ]]; then - if grep -q "^$key=*" "$file" 2>/dev/null; then - info_print "$key not updated." $WARN_FLAG - return - else - info_print "$key not set (empty input)." $WARN_FLAG - return - fi - fi - - if [[ "$isUpdated" == true ]]; then - if grep -Eq "^${key}=" "$file" 2>/dev/null; then - read -p "$key already set, overwrite? (y/N): " yn - - case "$yn" in - [Yy]*) - sed -i "s/^$key=.*/$key=$value/" "$file" - info_print "$key updated." $SUCCESS_FLAG - ;; - *) - info_print "$key not changed." $WARN_FLAG - ;; - esac - else - echo "$key=$value" >> "$file" - info_print "$key set." $SUCCESS_FLAG - fi - else - if grep -Eq "^${key}=" "$file" 2>/dev/null; then - sed -i "s/^$key=.*/$key=$value/" "$file" - else - echo "$key=$value" >> "$file" - fi - fi -} - -create_raw_line_variable() { - local line="$1" - local file="$2" - - if grep -Fxq "$line" "$file" 2>/dev/null; then - info_print "'$line' already defined as raw line." $WARN_FLAG - else - echo "$line" >> "$file" - info_print "'$line' added as raw line." $SUCCESS_FLAG - fi -} \ No newline at end of file diff --git a/libs/notifications.sh b/libs/notifications.sh deleted file mode 100644 index 3eaf275..0000000 --- a/libs/notifications.sh +++ /dev/null @@ -1,28 +0,0 @@ -source /usr/local/bin/libs/common.sh -source /etc/serverconfig/.env - -INSTALLED=$1 - -if [[ "--install" == $INSTALLED ]]; then - info_print "\n\ -==================================================\n\ - notifications Installation\n\ ---------------------------------------------------" - - ENV_LIST=("TELEGRAM_TOKEN" "TELEGRAM_CHAT_ID") - - for env in "${ENV_LIST[@]}"; do - read -p "Enter value for $env: " value - create_env_variable "$env" "$value" - done - - exit 0 -fi - -send_notification() { - local message="$1" - curl -X POST "https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage" \ - -d "chat_id=$TELEGRAM_CHAT_ID" \ - -d "text=$message" \ - -d "parse_mode=HTML" -} \ No newline at end of file diff --git a/scripts/docker-compose.sh b/scripts/docker-compose.sh deleted file mode 100644 index 14e09c5..0000000 --- a/scripts/docker-compose.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -INSTALLED=$1 -if [[ "--install" == $INSTALLED ]]; then - source /usr/local/bin/libs/common.sh - - info_print "\n\ -==================================================\n\ - docker-compose Installation\n\ ---------------------------------------------------" - - ENV_LIST=("EMAIL" "HOSTNAME") - - for env in "${ENV_LIST[@]}"; do - read -p "Enter value for $env: " value - create_env_variable "$env" "$value" - done - - source /etc/serverconfig/.env - - if [[ -f "$ETC_DIR/docker-compose.yml" ]]; then - docker compose -f "$ETC_DIR/docker-compose.yml" up -d --force-recreate --remove-orphans && \ - info_print "$ETC_DIR/docker-compose.yml is running." 6; - - else info_print "no docker-compose.yml found at $ETC_DIR" 3; - fi - exit 0; -fi \ No newline at end of file diff --git a/scripts/sshd-login.sh b/scripts/sshd-login.sh deleted file mode 100644 index 0395466..0000000 --- a/scripts/sshd-login.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -source /usr/local/bin/libs/common.sh -source /etc/serverconfig/.env - -INSTALLED=$1 -if [[ "--install" == $INSTALLED ]]; then - info_print "\n\ -==================================================\n\ - sshd-login Installation\n\ ---------------------------------------------------" - - login='session optional pam_exec.so /usr/local/bin/scripts/sshd-login.sh' - file='/etc/pam.d/common-session' - - if [[ ! -f "$file" ]]; then - info_print "$file doesn't found." $ERROR_FLAG - exit 1 - fi - - if ! grep -Fxq "$login" "$file"; then - echo "$login" >> "$file" - info_print "login command added to $file." $SUCCESS_FLAG - else - info_print "login command already added to $file." $WARN_FLAG - fi - exit 0; -fi - -source /usr/local/bin/libs/notifications.sh - -case "$PAM_TYPE" in - open_session) - PAYLOAD=$(printf "🚨 Login Event 🚨\nUser %s logged in from %s at %s." "$PAM_USER" "$PAM_RHOST" "$(date)") - ;; - close_session) - PAYLOAD=$(printf "🚨 Logout Event 🚨\nUser %s logged out from %s at %s." "$PAM_USER" "$PAM_RHOST" "$(date)") - ;; -esac - -if [ -n "$PAYLOAD" ] ; then - send_notification "$PAYLOAD" -fi \ No newline at end of file diff --git a/sshd-login.sh b/sshd-login.sh new file mode 100644 index 0000000..c93ad7c --- /dev/null +++ b/sshd-login.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +PROJECT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +readonly PROJECT_DIR 2>/dev/null + +source $PROJECT_DIR/utils.sh + +INSTALLED=$1 +if [[ "--install" == $INSTALLED ]]; then + log_info "sshd-login Installation" + + login="session optional pam_exec.so $PROJECT_DIR/sshd-login.sh" + file='/etc/pam.d/common-session' + + if [[ ! -f "$file" ]]; then + log_error "$file doesn't found." + exit 1 + fi + + if ! grep -Fxq "$login" "$file"; then + echo "$login" >>"$file" + log_success "login command added to $file." + else + log_warn "login command already added to $file." $WARN_FLAG + fi + exit 0 +fi + +case "$PAM_TYPE" in +open_session) + PAYLOAD=$(printf "🚨 Login Event 🚨\nUser %s logged in from %s at %s." "$PAM_USER" "$PAM_RHOST" "$(date)") + ;; +close_session) + PAYLOAD=$(printf "🚨 Logout Event 🚨\nUser %s logged out from %s at %s." "$PAM_USER" "$PAM_RHOST" "$(date)") + ;; +esac + +if [ -n "$PAYLOAD" ]; then + send_notification "$PAYLOAD" +fi diff --git a/utils.sh b/utils.sh new file mode 100644 index 0000000..b0d9bae --- /dev/null +++ b/utils.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# UTILITY FUNCTIONS & CONFIGURATION +# This script acts as a library (utils.sh) for other monitoring scripts. +# It handles logging, environment variables, and Telegram notifications. + +PROJECT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +readonly PROJECT_DIR 2>/dev/null + +readonly PROJECT_NAME="serverconfig" + +readonly REQ=("curl" "docker") + +readonly ENV_FILE="${PROJECT_DIR}/.env" + +readonly GREEN='\033[0;32m' +readonly RED='\033[0;31m' +readonly YELLOW='\033[1;33m' +readonly BLUE='\033[0;34m' +readonly NC='\033[0m' + +DATETIME_FORMAT="%d-%m-%Y %H:%M:%S" + +function log() { + local type="${1}" + local color="${2}" + local message="${3}" + echo -e "${color}[$(date +"$DATETIME_FORMAT")] [${type}]${NC} ${message}" +} + +function log_info() { log "INFO" "$BLUE" "$1"; } +function log_success() { log "OK " "$GREEN" "$1"; } +function log_error() { log "ERR " "$RED" "$1" >&2; } +function log_warn() { log "WARN " "$YELLOW" "$1" >&2; } + +# USING TELEGRAM (may change later) +function send_notification() { + local message="$1" + curl -X POST "https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage" \ + -d "chat_id=$TELEGRAM_CHAT_ID" \ + -d "text=$message" \ + -d "parse_mode=HTML" +} + +function env_variable() { + source $ENV_FILE + + local key="$1" + local value="$2" + + if [[ -z "$value" ]]; then + log_warn "$key not set." + fi + + if grep -Eq "^${key}=" "$ENV_FILE" 2>/dev/null; then + read -p "$key already set, overwrite? (y/N): " yn + case "$yn" in + [yY]*) + sed -i "s/^$key=.*/$key=$value/" "$ENV_FILE" + log_success "$key updated." + ;; + *) + log_info "$key not changed." + ;; + esac + else + echo "$key=$value" >> "$ENV_FILE" + log_success "$key created." + fi +} \ No newline at end of file