← Back to Documentation
Documentation
Deployment Guide
Comprehensive guide for deploying ad-blocking components in production environments.
Overview
This guide covers deployment strategies for all components in the ad-blocking repository, including Docker containerization, CI/CD pipelines, environment configuration, and best practices for production deployments.
Deployment Strategies
1. Docker Deployment
Pre-built Development Image
Use the pre-configured Docker image with all dependencies:
# Pull the image
docker pull jaysonknight/warp-env:ad-blocking
# Run container
docker run -it -v $(pwd):/workspace jaysonknight/warp-env:ad-blocking
Custom Production Image
Build a minimal production image:
# Dockerfile.production
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
# Copy and build only what you need
WORKDIR /app
COPY src/ ./src/
COPY data/ ./data/
# Build specific component
RUN cd src/rules-compiler-dotnet && dotnet publish -c Release -o /app/out
FROM mcr.microsoft.com/dotnet/runtime:10.0-alpine
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet", "RulesCompiler.Console.dll"]
Build and run:
docker build -f Dockerfile.production -t ad-blocking-compiler:latest .
docker run -v $(pwd)/rules:/app/rules ad-blocking-compiler:latest
Multi-stage Builds for Each Component
TypeScript/Deno:
FROM denoland/deno:2.0.0
WORKDIR /app
COPY src/rules-compiler-typescript/ .
RUN deno cache src/mod.ts
CMD ["deno", "task", "compile"]
.NET:
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY src/rules-compiler-dotnet/ .
RUN dotnet publish -c Release -o /app
FROM mcr.microsoft.com/dotnet/runtime:10.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "RulesCompiler.Console.dll"]
Python:
FROM python:3.12-slim
WORKDIR /app
COPY src/rules-compiler-python/ .
RUN pip install --no-cache-dir -e .
CMD ["rules-compiler"]
Rust:
FROM rust:1.70 AS builder
WORKDIR /app
COPY src/rules-compiler-rust/ .
RUN cargo build --release
FROM debian:bookworm-slim
COPY --from=builder /app/target/release/rules-compiler /usr/local/bin/
CMD ["rules-compiler"]
2. Docker Compose Deployment
Create a docker-compose.yml for orchestration:
version: '3.8'
services:
# Rules compilation service
rules-compiler:
build:
context: .
dockerfile: Dockerfile.production
volumes:
- ./rules:/app/rules
- ./Config:/app/Config
environment:
- CONFIG_PATH=/app/Config/compiler-config.yaml
restart: unless-stopped
# API service
api-service:
build:
context: .
dockerfile: src/adguard-api-dotnet/Dockerfile
environment:
- ADGUARD_AdGuard__ApiKey=${ADGUARD_API_KEY}
- ADGUARD_AdGuard__BaseUrl=https://api.adguard-dns.io
ports:
- "5000:5000"
restart: unless-stopped
# Scheduled compilation
compiler-cron:
build:
context: .
dockerfile: Dockerfile.cron
volumes:
- ./rules:/app/rules
- ./Config:/app/Config
environment:
- CRON_SCHEDULE=0 */6 * * * # Every 6 hours
restart: unless-stopped
Run with:
docker-compose up -d
docker-compose logs -f
3. Kubernetes Deployment
ConfigMap for Configuration
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: compiler-config
data:
compiler-config.yaml: |
name: Production Filter List
version: "1.0.0"
sources:
- name: EasyList
source: https://easylist.to/easylist/easylist.txt
type: adblock
transformations:
- Validate
- Deduplicate
- RemoveEmptyLines
- InsertFinalNewLine
Secret for API Keys
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: adguard-api-secret
type: Opaque
stringData:
api-key: your-api-key-here
Deployment
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: rules-compiler
spec:
replicas: 1
selector:
matchLabels:
app: rules-compiler
template:
metadata:
labels:
app: rules-compiler
spec:
containers:
- name: compiler
image: ad-blocking-compiler:latest
env:
- name: CONFIG_PATH
value: /config/compiler-config.yaml
- name: ADGUARD_AdGuard__ApiKey
valueFrom:
secretKeyRef:
name: adguard-api-secret
key: api-key
volumeMounts:
- name: config
mountPath: /config
- name: rules
mountPath: /app/rules
volumes:
- name: config
configMap:
name: compiler-config
- name: rules
persistentVolumeClaim:
claimName: rules-pvc
CronJob for Scheduled Compilation
# cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: rules-compiler-cron
spec:
schedule: "0 */6 * * *" # Every 6 hours
jobTemplate:
spec:
template:
spec:
containers:
- name: compiler
image: ad-blocking-compiler:latest
env:
- name: CONFIG_PATH
value: /config/compiler-config.yaml
volumeMounts:
- name: config
mountPath: /config
- name: rules
mountPath: /app/rules
restartPolicy: OnFailure
volumes:
- name: config
configMap:
name: compiler-config
- name: rules
persistentVolumeClaim:
claimName: rules-pvc
Apply:
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f deployment.yaml
kubectl apply -f cronjob.yaml
CI/CD Integration
GitHub Actions
Complete Workflow
# .github/workflows/deploy.yml
name: Build and Deploy
on:
push:
branches: [ main ]
tags: [ 'v*' ]
pull_request:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
component: [typescript, dotnet, python, rust]
steps:
- uses: actions/checkout@v4
- name: Test TypeScript
if: matrix.component == 'typescript'
run: |
cd src/rules-compiler-typescript
deno cache src/mod.ts
deno task test
- name: Test .NET
if: matrix.component == 'dotnet'
run: |
cd src/rules-compiler-dotnet
dotnet test RulesCompiler.slnx
- name: Test Python
if: matrix.component == 'python'
run: |
cd src/rules-compiler-python
pip install -e ".[dev]"
pytest
- name: Test Rust
if: matrix.component == 'rust'
run: |
cd src/rules-compiler-rust
cargo test
build:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile.production
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy to production
run: |
# Add your deployment commands here
echo "Deploying to production..."
Compile and Release Workflow
# .github/workflows/compile-rules.yml
name: Compile and Release Rules
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
workflow_dispatch:
jobs:
compile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Deno
uses: denoland/setup-deno@v1
with:
deno-version: v2.x
- name: Compile rules
run: |
cd src/rules-compiler-typescript
deno task compile -- -c ../../Config/compiler-config.yaml -r
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: compiled-rules
path: data/output/adguard_user_filter.txt
- name: Create Release
if: github.event_name == 'schedule'
uses: softprops/action-gh-release@v1
with:
tag_name: rules-${{ github.run_number }}
files: data/output/adguard_user_filter.txt
GitLab CI/CD
# .gitlab-ci.yml
stages:
- test
- build
- deploy
variables:
DOCKER_DRIVER: overlay2
test:typescript:
stage: test
image: denoland/deno:2.0.0
script:
- cd src/rules-compiler-typescript
- deno cache src/mod.ts
- deno task test
test:dotnet:
stage: test
image: mcr.microsoft.com/dotnet/sdk:10.0
script:
- cd src/rules-compiler-dotnet
- dotnet test RulesCompiler.slnx
test:python:
stage: test
image: python:3.12
script:
- cd src/rules-compiler-python
- pip install -e ".[dev]"
- pytest
test:rust:
stage: test
image: rust:1.70
script:
- cd src/rules-compiler-rust
- cargo test
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -f Dockerfile.production -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
deploy:production:
stage: deploy
image: alpine:latest
only:
- main
script:
- apk add --no-cache curl
- curl -X POST $ADGUARD_WEBHOOK_URL
Jenkins Pipeline
// Jenkinsfile
pipeline {
agent any
stages {
stage('Test') {
parallel {
stage('TypeScript') {
steps {
sh '''
cd src/rules-compiler-typescript
deno cache src/mod.ts
deno task test
'''
}
}
stage('.NET') {
steps {
sh '''
cd src/rules-compiler-dotnet
dotnet test RulesCompiler.slnx
'''
}
}
stage('Python') {
steps {
sh '''
cd src/rules-compiler-python
pip install -e ".[dev]"
pytest
'''
}
}
stage('Rust') {
steps {
sh '''
cd src/rules-compiler-rust
cargo test
'''
}
}
}
}
stage('Build') {
steps {
sh 'docker build -f Dockerfile.production -t ad-blocking:${BUILD_NUMBER} .'
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh '''
docker tag ad-blocking:${BUILD_NUMBER} ad-blocking:latest
docker push ad-blocking:latest
'''
}
}
}
}
Environment Configuration
Environment Variables
Rules Compilers
| Variable | Description | Default | Required |
|---|---|---|---|
CONFIG_PATH |
Path to configuration file | compiler-config.json |
No |
DEBUG |
Enable debug logging | false |
No |
RULES_DIR |
Output directory for rules | ./rules |
No |
RULESCOMPILER_Logging__LogLevel__Default |
.NET log level | Information |
No |
API Clients
| Variable | Description | Required |
|---|---|---|
ADGUARD_AdGuard__ApiKey |
AdGuard DNS API key | Yes |
ADGUARD_AdGuard__BaseUrl |
API base URL | No |
ADGUARD_API_TOKEN |
Legacy API token (Rust) | Yes (if not using ApiKey) |
ADGUARD_API_URL |
Legacy API URL (Rust) | No |
Configuration Files
Production Configuration Example
# config/production.yaml
name: Production Filter List
description: Production ad-blocking filter
version: "2.0.0"
homepage: https://github.com/yourusername/ad-blocking
license: GPL-3.0
sources:
- name: EasyList
source: https://easylist.to/easylist/easylist.txt
type: adblock
transformations:
- Validate
- RemoveModifiers
- name: EasyPrivacy
source: https://easylist.to/easylist/easyprivacy.txt
type: adblock
transformations:
- Validate
- RemoveModifiers
- name: AdGuard Base
source: https://raw.githubusercontent.com/AdguardTeam/FiltersRegistry/master/filters/filter_2_Base/filter.txt
type: adblock
transformations:
- Deduplicate
- RemoveEmptyLines
- TrimLines
- InsertFinalNewLine
- ConvertToAscii
exclusions_sources:
- config/whitelist.txt
Environment-Specific Configurations
# config/.env.production
ADGUARD_AdGuard__ApiKey=prod_api_key_here
CONFIG_PATH=/app/config/production.yaml
RULES_DIR=/app/rules
DEBUG=false
# config/.env.staging
ADGUARD_AdGuard__ApiKey=staging_api_key_here
CONFIG_PATH=/app/config/staging.yaml
RULES_DIR=/app/rules
DEBUG=true
Load with:
docker run --env-file config/.env.production ad-blocking:latest
Production Best Practices
1. Security
Secrets Management:
# Use Docker secrets
echo "your-api-key" | docker secret create adguard_api_key -
# Reference in docker-compose.yml
services:
api-service:
secrets:
- adguard_api_key
environment:
- ADGUARD_AdGuard__ApiKey_FILE=/run/secrets/adguard_api_key
secrets:
adguard_api_key:
external: true
Use HashiCorp Vault:
# Store secret
vault kv put secret/adguard api_key=your-api-key
# Retrieve in application
export ADGUARD_AdGuard__ApiKey=$(vault kv get -field=api_key secret/adguard)
2. Monitoring
Health Checks:
# Add health check to Dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
Logging:
# docker-compose.yml
services:
rules-compiler:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Prometheus Metrics:
// Add to .NET application
services.AddHealthChecks();
app.MapHealthChecks("/health");
app.MapMetrics(); // Prometheus metrics endpoint
3. Performance
Resource Limits:
# docker-compose.yml
services:
rules-compiler:
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '1'
memory: 1G
Caching:
# Cache dependencies in layers
FROM denoland/deno:2.0.0
WORKDIR /app
# Copy dependency files first
COPY deno.json deno.lock ./
RUN deno cache --lock=deno.lock
# Then copy source
COPY . .
4. Backup and Recovery
Volume Backups:
# Backup rules volume
docker run --rm \
-v ad-blocking_rules:/data \
-v $(pwd)/backups:/backup \
alpine tar czf /backup/rules-backup-$(date +%Y%m%d).tar.gz -C /data .
# Restore
docker run --rm \
-v ad-blocking_rules:/data \
-v $(pwd)/backups:/backup \
alpine tar xzf /backup/rules-backup-20250101.tar.gz -C /data
Automated Backups:
# backup-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: rules-backup
spec:
schedule: "0 2 * * *" # Daily at 2 AM
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: alpine:latest
command:
- /bin/sh
- -c
- tar czf /backup/rules-$(date +%Y%m%d).tar.gz -C /data .
volumeMounts:
- name: rules
mountPath: /data
- name: backup
mountPath: /backup
restartPolicy: OnFailure
volumes:
- name: rules
persistentVolumeClaim:
claimName: rules-pvc
- name: backup
persistentVolumeClaim:
claimName: backup-pvc
Scaling Strategies
Horizontal Scaling
# kubernetes-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: rules-compiler-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: rules-compiler
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Load Balancing
# nginx-lb.conf
upstream compilers {
least_conn;
server compiler1:5000;
server compiler2:5000;
server compiler3:5000;
}
server {
listen 80;
location / {
proxy_pass http://compilers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Troubleshooting Deployment Issues
Container Startup Failures
# Check logs
docker logs <container_id>
# Inspect container
docker inspect <container_id>
# Check resource constraints
docker stats
Network Issues
# Test connectivity
docker exec <container_id> ping api.adguard-dns.io
# Check DNS resolution
docker exec <container_id> nslookup api.adguard-dns.io
# Inspect network
docker network inspect <network_name>
Permission Issues
# Run with specific user
docker run --user $(id -u):$(id -g) ad-blocking:latest
# Fix volume permissions
docker run --rm -v ad-blocking_rules:/data alpine chown -R 1000:1000 /data
Related Documentation
License
GPLv3 - See LICENSE for details.