Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,13 @@ GID=1000

# Grafana admin password
GRAFANA_PASSWORD=your-secure-password

# ===========================================
# External Monitoring (Optional)
# ===========================================
# Set LOKI_URL to connect Promtail to an external Loki instance
# instead of running a local Loki container.
# Use 'make start-monitoring-external' to start in external mode.

# LOKI_URL=https://loki.provider.com/loki/api/v1/push
# LOKI_TENANT_ID=nginx-security
49 changes: 49 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Publish

on:
push:
branches: [master]
tags: ['v*']

env:
IMAGE_NAME: viktorpalchynskyi/nginx-security
Comment on lines +8 to +9
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I set it through enviroment, so you need to remove


jobs:
publish:
runs-on: ubuntu-latest
Comment on lines +12 to +13
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add there enviroment, in order to get limited secrets

Suggested change
publish:
runs-on: ubuntu-latest
publish:
environment: Production
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,prefix=sha-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}

- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
54 changes: 54 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Verify

on:
push:
branches: [master]
pull_request:
branches: [master]

env:
IMAGE_NAME: viktorpalchynskyi/nginx-security

jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build image for testing
uses: docker/build-push-action@v6
with:
context: .
load: true
tags: ${{ env.IMAGE_NAME }}:test
cache-from: type=gha
cache-to: ${{ github.event.pull_request.head.repo.fork != true && 'type=gha,mode=max' || '' }}

- name: Start test environment
run: |
docker network create test-net
docker run -d --name httpbin --network test-net kennethreitz/httpbin:latest
docker run -d --name nginx-security \
--network test-net \
-e BACKEND=http://httpbin:80 \
-p 8080:8080 \
${{ env.IMAGE_NAME }}:test
echo "Waiting for nginx to start..."
sleep 15
curl -sf http://localhost:8080/healthz || (docker logs nginx-security && exit 1)

- name: Run security tests
run: ./scripts/test-security.sh localhost:8080 http

- name: Run false positive tests
run: ./scripts/test-false-positives.sh localhost:8080 http

- name: Stop test environment
if: always()
run: |
docker stop nginx-security httpbin 2>/dev/null || true
docker rm nginx-security httpbin 2>/dev/null || true
docker network rm test-net 2>/dev/null || true
40 changes: 34 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help build run run-ssl stop-standalone health-standalone start stop restart test test-security test-false-pos logs logs-audit status bans unban-all health clean start-monitoring stop-monitoring health-monitoring
.PHONY: help build run run-ssl stop-standalone health-standalone start stop restart test test-security test-false-pos logs logs-audit status bans unban-all health clean start-monitoring stop-monitoring health-monitoring start-monitoring-external health-monitoring-external

IMAGE_NAME ?= neolab/nginx-security
IMAGE_TAG ?= latest
Expand All @@ -21,9 +21,11 @@ help:
@echo " make restart - Restart all services"
@echo ""
@echo " Monitoring (optional add-on):"
@echo " make start-monitoring - Start monitoring stack"
@echo " make stop-monitoring - Stop monitoring stack"
@echo " make health-monitoring - Check monitoring health"
@echo " make start-monitoring - Start full monitoring stack (standalone)"
@echo " make start-monitoring-external - Start monitoring (external Loki/Prometheus)"
@echo " make stop-monitoring - Stop monitoring stack"
@echo " make health-monitoring - Check monitoring health (standalone)"
@echo " make health-monitoring-external - Check monitoring health (external)"
@echo ""
@echo " Testing:"
@echo " make test - Run all tests"
Expand Down Expand Up @@ -104,21 +106,47 @@ restart:
# ===========================================

start-monitoring:
docker compose -f docker-compose.monitoring.yml up -d
docker compose -f docker-compose.monitoring.yml --profile standalone --profile grafana up -d
@echo "Connecting nginx-security to monitoring network..."
@docker network connect nginx-security-monitoring $(CONTAINER_NAME) 2>/dev/null || true
@echo "Waiting for monitoring services to start..."
@sleep 15
@$(MAKE) health-monitoring

start-monitoring-external:
@if [ -z "$(LOKI_URL)" ]; then \
echo "ERROR: LOKI_URL is not set."; \
echo "Set it in .env or export it: export LOKI_URL=https://loki.provider.com/loki/api/v1/push"; \
exit 1; \
fi
@echo "Starting external monitoring mode..."
@echo " Loki URL: $$(echo '$(LOKI_URL)' | sed -E 's|://[^@]*@|://***@|')"
@docker compose -f docker-compose.monitoring.yml stop loki grafana 2>/dev/null || true
@docker compose -f docker-compose.monitoring.yml rm -f loki grafana 2>/dev/null || true
docker compose -f docker-compose.monitoring.yml up -d nginx-exporter crowdsec promtail
@echo "Connecting nginx-security to monitoring network..."
@docker network connect nginx-security-monitoring $(CONTAINER_NAME) 2>/dev/null || true
@echo "Waiting for monitoring services to start..."
@sleep 15
@$(MAKE) health-monitoring-external

stop-monitoring:
docker compose -f docker-compose.monitoring.yml --profile standalone --profile grafana down
docker compose -f docker-compose.monitoring.yml down

health-monitoring:
@echo "Checking monitoring health..."
@echo "Checking monitoring health (standalone)..."
@curl -sf http://localhost:9113/metrics > /dev/null 2>&1 && echo "nginx-exporter: OK" || echo "nginx-exporter: FAIL"
@curl -sf http://localhost:6060/metrics > /dev/null 2>&1 && echo "crowdsec: OK" || echo "crowdsec: FAIL"
@curl -sf http://localhost:3100/ready > /dev/null 2>&1 && echo "loki: OK" || echo "loki: FAIL"
@curl -sf http://localhost:3000/api/health > /dev/null 2>&1 && echo "grafana: OK" || echo "grafana: FAIL"

health-monitoring-external:
@echo "Checking monitoring health (external)..."
@curl -sf http://localhost:9113/metrics > /dev/null 2>&1 && echo "nginx-exporter: OK" || echo "nginx-exporter: FAIL"
@curl -sf http://localhost:6060/metrics > /dev/null 2>&1 && echo "crowdsec: OK" || echo "crowdsec: FAIL"
@docker ps --format '{{.Names}}' | grep -q promtail && echo "promtail: RUNNING" || echo "promtail: NOT RUNNING"
@docker ps --format '{{.Names}}' | grep -q loki && echo "WARNING: loki is running (should not be in external mode)" || echo "loki: NOT RUNNING (expected)"

# ===========================================
# Testing
Expand Down
Loading