diff --git a/.gitignore b/.gitignore index 79b0d0f..26977b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target /rules +/config template.json default.json \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index e99c220..bb1bf19 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,23 +6,27 @@ services: container_name: sb-ruleset-sync restart: unless-stopped - # Mount volumes: - # - The local `rules` directory is mounted into the container, so downloaded - # files persist between container restarts. - # - The `template.json` is mounted as read-only for security. volumes: - - ./template.json:/config/template.json:ro + # Mount the directory with original `template.json` file. + - ./config:/config + # Mount the directory for the downloaded rule files. - ./rules:/rules environment: + # Timezone for logs and cron. - TZ=Europe/Moscow - # Optional: Set the user and group ID for the 'app' user inside the container. - # Match this to your host user (`id -u` and `id -g`) to avoid file permission - # issues on the mounted `./rules` volume. + # Cron schedule. Default is 2:10 AM daily. + - CRON_SCHEDULE="10 2 * * *" + # User/Group IDs to avoid permission issues on volumes. - PUID=1000 - PGID=1000 - # A healthcheck to ensure the cron daemon is running. + # --- URL REWRITING (REQUIRED) --- + # The domain of your server that will host the rules. + - DOMAIN=my.server.com + # The path on your server where the rules are accessible. + - RULE_PATH=rules + healthcheck: test: ["CMD", "pgrep", "crond"] interval: 1m diff --git a/docker/Dockerfile b/docker/Dockerfile index 4ff1f24..4065b60 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,3 @@ -# docker/Dockerfile - # ============================================================================== # STAGE 1: Build # ============================================================================== @@ -10,26 +8,24 @@ RUN apk add --no-cache musl-dev gcc WORKDIR /app -# 1. Create a dummy binary project. +# 1. Create a dummy binary project for dependency caching. RUN mkdir src RUN echo "fn main() {}" > src/main.rs # 2. Copy the dependency manifests. COPY Cargo.toml Cargo.lock ./ -# 3. Build the dependencies. This will compile all dependencies from -# Cargo.lock and the empty main.rs. +# 3. Build the dependencies. RUN cargo build --release # 4. Now, copy the actual application source code. COPY src ./src -# 5. Build the real application. This will be very fast as all dependencies -# are already compiled and cached. +# 5. Build the real application. RUN cargo build --release # ============================================================================== -# STAGE 2: Create the final, minimal production image +# STAGE 2: Create the final production image # ============================================================================== FROM alpine:3.22 AS final @@ -52,9 +48,9 @@ COPY --from=builder /app/target/release/sb-ruleset-sync /usr/local/bin/ruleset-s COPY ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh -# Create necessary directories and set ownership +# Create necessary directories and set ownership for volumes RUN mkdir -p /config /rules && \ - chown -R app:app /rules + chown -R app:app /config /rules # Set the entrypoint for the container ENTRYPOINT ["entrypoint.sh"] \ No newline at end of file diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 618e1b0..8c19259 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,33 +1,46 @@ #!/bin/sh -set -e # Exit immediately if a command exits with a non-zero status. +set -e -# Define the command to be executed by cron or manually -APP_CMD="/usr/local/bin/ruleset-sync -i /config/template.json -o /rules" +# --- Environment Variable Defaults --- +DOMAIN=${DOMAIN:-} +RULE_PATH=${RULE_PATH:-} -# === Manual Run === -# If the first argument is "manual", run the sync once and exit. +# --- Build the Command --- +# This command is now used for both the initial run and the cron job. +APP_CMD="/usr/local/bin/ruleset-sync \ + --input-config /config/template.json \ + --rules-dir /rules \ + --output-config /config/default.json \ + --domain ${DOMAIN} \ + --rule-path ${RULE_PATH}" + +# --- Manual Run Mode --- +# This allows for on-demand execution without restarting the container. if [ "$1" = "manual" ]; then echo "[$(date +"%Y-%m-%d %H:%M:%S")] Running one-time manual sync..." - # Execute the command as the non-root 'app' user - su-exec app:app ${APP_CMD} + su-exec app:app sh -c "${APP_CMD}" exit 0 fi -# === Cron Setup === -# This section runs as root to set up the cron job. +# =================================================================== +# Initial Synchronization on Container Start +# =================================================================== +echo "--- Running initial synchronization on container start ---" +# Execute the command once immediately. +# We run it as the non-root 'app' user to ensure correct file permissions. +su-exec app:app sh -c "${APP_CMD}" +echo "--- Initial synchronization finished ---" +# =================================================================== + +# --- Cron Setup --- +# This section runs after the initial sync is complete. echo "Setting up cron job with schedule: ${CRON_SCHEDULE}" - -# Remove any existing crontab crontab -d || true +echo "${CRON_SCHEDULE} su-exec app:app sh -c '${APP_CMD}' > /proc/1/fd/1 2>/proc/1/fd/2" | crontab - -# Add the new cron job. It will run the command as the 'app' user -# and redirect stdout/stderr to the container's log stream. -echo "${CRON_SCHEDULE} su-exec app:app ${APP_CMD} > /proc/1/fd/1 2>/proc/1/fd/2" | crontab - - -# Start the cron daemon in the foreground. -# This keeps the container running and handles executing the scheduled jobs. -# Logs from crond itself and the script's output will go to Docker logs. +# --- Start Cron Daemon --- +# This must be the last command. It keeps the container running. echo "Starting cron daemon..." exec crond -f -l 8 \ No newline at end of file