[Self-Hosted] 로그와 메트릭 모니터링 Grafana + Alloy + Prometheus + Loki를 설치해보자 (feat. Caddy)
![[Self-Hosted] 로그와 메트릭 모니터링 Grafana + Alloy + Prometheus + Loki를 설치해보자 (feat. Caddy)](/content/images/size/w2000/2025/04/caddy-grafana-stack.png)
Caddy의 메트릭과 액세스 로그를 모니터링하려고 설치했다.
처음에는 ELK Stack을 설치하려고 했는데... SECCOMP 문제로 실패했다.
새롭게 찾은 대안이 Grafana + Alloy + Prometheus + Loki이다.
Caddy | 리버스 프록시 |
Grafana | 데이터 시각화 |
Alloy | 데이터 처리 |
Prometheus | 메트릭 수집 및 쿼리 |
Loki | 로그 수집 및 쿼리 |
설치 환경
- Synology DS220+ (DSM 7.2.2-72806 Update 3)
- Docker Engine 24.0.2
- Docker Compose 2.29.6
🔧 Caddyfile 수정하기
{
# Global options
admin 0.0.0.0:2019 # networks: host가 아닌 도커 컨테이너를 사용 중이라면 필요함
metrics {
# per_host # 호스트별로 메트릭 수집
}
log access-json { # 이름 수정 가능함
include http.log.access.reverse_proxy # reverse_proxy 로거를 수집함
output file /var/log/caddy/access.log { # 경로 수정 가능함
roll_size 1Gib
roll_keep 5
roll_keep_for 90d
}
format json
level INFO
}
}
# reverse_proxy options
example.com {
log reverse_proxy # 로거 이름 수정 가능함
reverse_proxy example:80
}
Caddyfile 예시
Prometheus에서 사용할 metrics API와 Alloy에서 사용할 log 파일이 필요하다.
Caddy에서 metrics API와 logging은 기본적으로 비활성화 되어 있다.
- 할 일
- Admin API 활성화
- log 파일 생성
metrics 옵션을 설정하고 나면 Admin API를 사용할 수 있다.
log 옵션을 설정하고 나면 log 파일이 생성된다.
🔧 Caddy의 compose.yml 수정하기
services:
caddy:
image: 'caddy:latest'
container_name: caddy
hostname: caddy
restart: unless-stopped
ports:
- 2019:2019 # 포트 개방이 필요함
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./srv:/srv
- ./data:/data
- ./config:/config
- /path/to:/var/log/caddy // 원하는 경로로 수정하기 (Alloy가 사용할 log 파일)
environment:
- TZ=Asia/Seoul
caddy/compose.yml 예시
Caddy의 기본 Admin API 주소는 localhost:2019로 되어 있다.
도커 컨테이너로 운영 중일 때는 localhost의 주소가 컨테이너마다 다르기 때문에 Prometheus에서 Caddy의 localhost:2019
로 API 요청을 할 수가 없다. 그래서 Admin API 주소를 0.0.0.0:2019
로 바꾸는 것이다. 그럼 컨테이너의 2019 포트를 개방해야 한다.
Alloy에 사용할 Caddy의 log 파일을 로컬 볼륨에 마운트한다. 이 경로는 Alloy의 compose.yml 파일에서도 동일하게 사용한다.
Caddyfile과 compose.yml 파일 수정이 모두 끝났으면
curl http://내부아이피:2019/metrics
브라우저에서 접속하거나 curl 명령어를 이용해서 metrics이 정상적으로 출력되는지 확인한다.

Monitoring Caddy with Prometheus metrics

log
🚨 Caddy 오류 해결
만약 위와 같은 오류가 뜬다면, 포트 개방이 안 되어 있다는 뜻이다.
Caddy 도커 컨테이너의 2019 포트를 개방한 다음에 다시 시도한다.
caddy reload 명령어를 실행하고 위의 오류가 뜬다면 --address localhost:2019
옵션을 커맨드에 같이 입력한다.
Caddy 도커 컨테이너의 포트가 개방되어 있는지 확인하고, admin 0.0.0.0:2019
옵션이 적용되었는지 확인한다.
⚙️ 설정 파일 구성하기
폴더 구조
📦 grafana-stack
├─ config
│ ├─ alloy
│ │ └─ config.alloy
│ ├─ grafana
│ │ ├─ datasources
│ │ │ └─ datasource.yml
│ │ └─ grafana.ini
│ └─ prometheus
│ └─ prometheus.yml
└─ compose.yml
폴더 구조
config.alloy
loki.source.file "caddy_access_logs" {
targets = [{
__path__ = "/var/log/access.log",
}]
forward_to = [loki.process.access_logs.receiver]
}
loki.process "access_logs" {
forward_to = [loki.write.loki.receiver]
}
loki.write "loki" {
endpoint {
url = "http://grafana-loki:3100/loki/api/v1/push"
}
external_labels = {
app = "caddy",
}
}
config.alloy 예시

loki components

prometheus components
datasource.yml
apiVersion: 1
datasources:
- name: Loki
type: loki
access: proxy
orgId: 1
url: http://grafana-loki:3100
basicAuth: false
isDefault: true
version: 1
editable: true
- name: Prometheus
type: prometheus
url: http://grafana-prometheus:9090
isDefault: false
access: proxy
editable: true
datasource.yml 예시
grafana.ini
[analytics]
reporting_enabled = false
[auth.anonymous]
enabled = true
org_role = Admin
[explore]
enabled = true
[users]
default_theme = dark
grafana.ini 예시

Configure Grafana
prometheus.yml
global:
scrape_interval: 15s
scrape_timeout: 10s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets:
- localhost:9093
scheme: http
timeout: 10s
api_version: v1
scrape_configs:
- job_name: prometheus
honor_timestamps: true
scrape_interval: 15s
scrape_timeout: 10s
metrics_path: /metrics
scheme: http
static_configs:
- targets:
- localhost:9090
- job_name: caddy
static_configs:
- targets:
- caddy:2019
prometheus.yml 예시
⚙️ compose.yml 작성하기
volumes:
grafana_data:
name: grafana_data
grafana_prometheus_data:
name: grafana_prometheus_data
services:
grafana-loki:
image: 'grafana/loki:latest'
container_name: grafana-loki
hostname: grafana-loki
restart: unless-stopped
command:
- -config.file=/etc/loki/local-config.yaml
ports:
- 3100:3100
environment:
- TZ=Asia/Seoul
grafana-alloy:
image: 'grafana/alloy:latest'
container_name: grafana-alloy
hostname: grafana-alloy
restart: unless-stopped
command:
- run
- /etc/alloy/config.alloy
- --storage.path=/var/lib/alloy/data
- --server.http.listen-addr=0.0.0.0:12345
ports:
- 12345:12345
volumes:
- ./config/alloy:/etc/alloy
- /path/to:/var/log // caddy/compose.yml에서 설정한 로그 경로
environment:
- TZ=Asia/Seoul
depends_on:
- grafana-loki
grafana-prometheus:
image: 'prom/prometheus:latest'
container_name: grafana-prometheus
hostname: grafana-prometheus
restart: unless-stopped
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --web.enable-lifecycle
ports:
- 9091:9090
volumes:
- ./config/prometheus:/etc/prometheus
- grafana_prometheus_data:/prometheus
environment:
- TZ=Asia/Seoul
grafana:
image: 'grafana/grafana:latest'
container_name: grafana
hostname: grafana
restart: unless-stopped
command:
- --config=/etc/grafana-config/grafana.ini
ports:
- 3000:3000
volumes:
- grafana_data:/var/lib/grafana
- ./config/grafana:/etc/grafana-config
- ./config/grafana/datasources:/etc/grafana/provisioning/datasources
environment:
- TZ=Asia/Seoul
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/healthz']
interval: 1s
timeout: 10s
retries: 5
grafana-stack/compose.yml 예시
Docker Compose example
실행하기
docker compose up -d
http://내부아이피:3000
으로 접속해서 대시보드가 잘 뜨는지 확인한다.
✅ Alloy 확인하기


http://내부아이피:12345
로 접속해서 각 작업의 상태와 종속성을 확인할 수 있다.
✅ Prometheus 확인하기


http://내부아이피:9090
으로 접속해서 metrics API 연결이 잘 되고 있는지 확인할 수 있다.
🚨 Prometheus 오류 해결
- 주소 설정이 잘 되어 있는지 확인한다.
- 같은 도커 네트워크에 연결되어 있는지 확인한다.
- Caddy Admin API 주소가
0.0.0.0:2019
로 설정되어 있는지 확인한다. - Caddy 도커 컨테이너의 2019 포트가 개방되어 있는지 확인한다.
✅ Grafana 데이터 소스 확인하기

알려준 예시 설정대로 했다면 위에 사진처럼 나온다.

각 데이터 소스를 눌러서 맨 아래로 내리면 Save & test가 있다.
눌러서 잘 되는지 확인한다.


왼쪽 메뉴에서 Drilldown > Metrics, Logs을 눌러서 메트릭과 로그가 잘 뜨는지 확인한다.
🚨 Grafana 오류 해결
- 주소 설정이 잘 되어 있는지 확인한다.
- 같은 도커 네트워크에 연결되어 있는지 확인한다.
⚙️ 대시보드 추가하기


Create dashboard을 누르고 Import dashboard를 누른다.


위 사이트에 접속해서 대시보드를 다운로드한 다음에 업로드한다.

위 사진처럼 나온다면 잘 적용된 것이다.
만약, Caddyfile에서 per_host
옵션을 활성화했다면 각 host가 전부 떠버려서 이상하게 보인다.

이렇게 이상하게 뜬다면 각 패널을 직접 수정해야 한다.

Edit을 누르면 쿼리 수정 화면이 나온다.

sum(caddy_http_requests_total{instance=~"$host", handler=~"$handler"})
sum() 함수를 이용해서 전부 더하면 된다.
다른 패널도 마찬가지로 sum() 함수를 사용하면 된다.
Monitoring Caddy Server with Grafana (Prometheus + Loki) on Debian