commit f3b9d45ca9cb8c3043f06a57bf7259ca32611048 Author: Florian RICHER Date: Tue Oct 25 13:34:44 2022 +0200 First commit diff --git a/.docker-compose.yml.swp b/.docker-compose.yml.swp new file mode 100644 index 0000000..c43a283 Binary files /dev/null and b/.docker-compose.yml.swp differ diff --git a/cloud/docker-compose.yml b/cloud/docker-compose.yml new file mode 100644 index 0000000..dece1d7 --- /dev/null +++ b/cloud/docker-compose.yml @@ -0,0 +1,66 @@ +version: '3' + +services: + db: + image: postgres:14 + restart: always + container_name: nextcloud_db + networks: + - internal + volumes: + - db:/var/lib/postgresql/data + environment: + - POSTGRES_PASSWORD=nextcloud + - POSTGRES_DB=nextcloud + - POSTGRES_USER=nextcloud + + nextcloud: + image: nextcloud + restart: always + container_name: nextcloud + networks: + - proxy + - internal + depends_on: + - db + volumes: + - nextcloud:/var/www/html + labels: + - "traefik.enable=true" + - "traefik.http.middlewares.nextcloud-regex-redirect.redirectregex.permanent=true" + - "traefik.http.middlewares.nextcloud-regex-redirect.redirectregex.regex=https://(.*)/.well-known/(card|cal)dav" + - "traefik.http.middlewares.nextcloud-regex-redirect.redirectregex.replacement=https://$$1/remote.php/dav/" + - "traefik.http.middlewares.nextcloud-headers.headers.frameDeny=true" + - "traefik.http.middlewares.nextcloud-headers.headers.sslRedirect=true" + - "traefik.http.middlewares.nextcloud-headers.headers.contentTypeNosniff=true" + - "traefik.http.middlewares.nextcloud-headers.headers.stsIncludeSubdomains=true" + - "traefik.http.middlewares.nextcloud-headers.headers.stsPreload=true" + - "traefik.http.middlewares.nextcloud-headers.headers.stsSeconds=31536000" + - "traefik.http.middlewares.nextcloud-headers.headers.referrerPolicy=same-origin" + - "traefik.http.middlewares.nextcloud-headers.headers.browserXssFilter=true" + - "traefik.http.middlewares.nextcloud-headers.headers.customRequestHeaders.X-Forwarded-Proto=https" + - "traefik.http.middlewares.nextcloud-headers.headers.customRequestHeaders.X-Robots-Tag=none" + - "traefik.http.middlewares.nextcloud-headers.headers.customFrameOptionsValue=SAMEORIGIN" + - "traefik.http.routers.nextcloud-secure.entrypoints=https" + - "traefik.http.routers.nextcloud-secure.rule=Host(`mycld.mrdev023.fr`)" + - "traefik.http.routers.nextcloud-secure.tls=true" + - "traefik.http.routers.nextcloud-secure.tls.certresolver=sslResolver" + - "traefik.http.routers.nextcloud-secure.middlewares=nextcloud-regex-redirect,nextcloud-headers" + # - "traefik.http.routers.nextcloud-secure.service=nextcloud" + # - "traefik.http.services.nextcloud.loadbalancer.server.port=9002" + - "traefik.docker.network=proxy" + environment: + - POSTGRES_PASSWORD=nextcloud + - POSTGRES_DATABASE=nextcloud + - POSTGRES_USER=nextcloud + - POSTGRES_HOST=db + - OVERWRITEPROTOCOL=https + +volumes: + nextcloud: + db: + +networks: + internal: + proxy: + external: true diff --git a/config/.gitignore b/config/.gitignore new file mode 100644 index 0000000..a23708f --- /dev/null +++ b/config/.gitignore @@ -0,0 +1 @@ +acme.json \ No newline at end of file diff --git a/config/traefik.yml b/config/traefik.yml new file mode 100644 index 0000000..8732cd2 --- /dev/null +++ b/config/traefik.yml @@ -0,0 +1,49 @@ +log: + level: DEBUG + +api: + dashboard: true + +accessLog: + filePath: "/var/log/traefik/access.log" + format: json + +entryPoints: + http: + address: ":80" + http: + redirections: + entryPoint: + to: https + scheme: https + https: + address: ":443" + metrics: + address: ":8080" + +metrics: + prometheus: + entryPoint: metrics + buckets: + - 0.1 + - 0.3 + - 1.2 + - 5.0 + addEntryPointsLabels: true + addServicesLabels: true + +providers: + docker: + endpoint: "unix:///var/run/docker.sock" + exposedByDefault: false + +certificatesResolvers: + sslResolver: + acme: + email: florian.richer.97@outlook.com + tlschallenge: true + storage: acme.json + keyType: RSA4096 + #caServer: "https://acme-staging-v02.api.letsencrypt.org/directory" + httpChallenge: + entryPoint: http diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..98e013b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,113 @@ +version: '3' + +services: + traefik: + image: traefik:latest + container_name: traefik + restart: unless-stopped + security_opt: + - no-new-privileges:true + networks: + - proxy + ports: + - 80:80 + - 443:443 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./config/traefik.yml:/traefik.yml:ro + - ./config/acme.json:/acme.json + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + labels: + - "traefik.enable=true" + - "traefik.http.middlewares.traefik-auth.basicauth.users=mrdev023:$$2y$$05$$t51tXUW6zO9dndSK1JEFS.utJ3th/RYVSgDlouOZhUigjbkTX1zQC$$" + - "traefik.http.middlewares.traefik-stripprefix.stripprefix.prefixes=/traefik" + - "traefik.http.routers.traefik-secure.entrypoints=https" + - "traefik.http.routers.traefik-secure.rule=Host(`dash.mrdev023.fr`) && (PathPrefix(`/traefik`) || PathPrefix(`/api`))" + - "traefik.http.middlewares.tls-rep.redirectregex.permanent=true" + - "traefik.http.middlewares.tls-header.headers.SSLRedirect=true" + - "traefik.http.middlewares.tls-header.headers.forceSTSHeader=true" + - "traefik.http.middlewares.tls-header.headers.STSSeconds=315360000" + - "traefik.http.middlewares.tls-header.headers.STSIncludeSubdomains=true" + - "traefik.http.middlewares.tls-header.headers.STSPreload=true" + - "traefik.http.middlewares.tls-header.headers.browserXSSFilter=true" + - "traefik.http.middlewares.tls-header.headers.contentTypeNosniff=true" + - "traefik.http.middlewares.tls-header.headers.frameDeny=true" + - "traefik.http.middlewares.tls-header.headers.customFrameOptionsValue=SAMEORIGIN" + - "traefik.http.middlewares.tls-header.headers.featurePolicy=accelerometer 'none'; ambient-light-sensor 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; usb 'none'; midi 'none'; sync-xhr 'none'; vr 'none'" + - "traefik.http.middlewares.tls-header.headers.referrerPolicy=strict-origin-when-cross-origin" + - "traefik.http.middlewares.tls-chain.chain.middlewares=tls-rep,tls-header" + - "traefik.http.routers.traefik-secure.middlewares=traefik-stripprefix,tls-chain,traefik-auth" + - "traefik.http.routers.traefik-secure.tls=true" + - "traefik.http.routers.traefik-secure.tls.certresolver=sslResolver" + - "traefik.http.routers.traefik-secure.service=api@internal" + + prometheus: + image: prom/prometheus:latest + restart: unless-stopped + container_name: prometheus + volumes: + - ./prometheus/:/etc/prometheus/ + - prometheus:/prometheus + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + command: + - "--web.route-prefix=/" + - "--web.external-url=https://dash.mrdev023.fr/prometheus" + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus" + - "--web.console.libraries=/usr/share/prometheus/console_libraries" + - "--web.console.templates=/usr/share/prometheus/consoles" + networks: + - proxy + - internal + labels: + - "traefik.enable=true" + - "traefik.http.middlewares.prometheus-auth.basicauth.users=mrdev023:$$2y$$05$$t51tXUW6zO9dndSK1JEFS.utJ3th/RYVSgDlouOZhUigjbkTX1zQC$$" + - "traefik.http.middlewares.prometheus-stripprefix.stripprefix.prefixes=/prometheus" + - "traefik.http.routers.prometheus-secure.entrypoints=https" + - "traefik.http.routers.prometheus-secure.rule=Host(`dash.mrdev023.fr`) && PathPrefix(`/prometheus`)" + - "traefik.http.routers.prometheus-secure.middlewares=tls-chain,prometheus-stripprefix,prometheus-auth" + - "traefik.http.routers.prometheus-secure.tls=true" + - "traefik.http.routers.prometheus-secure.tls.certresolver=sslResolver" + - "traefik.http.routers.prometheus-secure.service=prometheus" + - "traefik.http.services.prometheus.loadbalancer.server.port=9090" + - "traefik.docker.network=proxy" + + grafana: + image: grafana/grafana:latest + restart: unless-stopped + container_name: grafana + volumes: + - grafana:/var/lib/grafana + - ./grafana/provisioning:/etc/grafana/provisioning + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + env_file: + - grafana.env + depends_on: + - prometheus + networks: + - proxy + - internal + labels: + - "traefik.enable=true" + - "traefik.http.middlewares.grafana-auth.basicauth.users=mrdev023:$$2y$$05$$t51tXUW6zO9dndSK1JEFS.utJ3th/RYVSgDlouOZhUigjbkTX1zQC$$" + - "traefik.http.middlewares.grafana-stripprefix.stripprefix.prefixes=/grafana" + - "traefik.http.routers.grafana-secure.entrypoints=https" + - "traefik.http.routers.grafana-secure.rule=Host(`dash.mrdev023.fr`) && PathPrefix(`/grafana`)" + - "traefik.http.routers.grafana-secure.middlewares=tls-chain,grafana-stripprefix,grafana-auth" + - "traefik.http.routers.grafana-secure.tls=true" + - "traefik.http.routers.grafana-secure.tls.certresolver=http" + - "traefik.http.routers.grafana-secure.service=grafana" + - "traefik.http.services.grafana.loadbalancer.server.port=3000" + - "traefik.docker.network=web" + +networks: + internal: + proxy: + external: true + +volumes: + prometheus: + grafana: diff --git a/firewall b/firewall new file mode 100755 index 0000000..f96aab7 --- /dev/null +++ b/firewall @@ -0,0 +1,74 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: firewall rules +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start daemon at boot time +# Description: Enable service provided by daemon. +### END INIT INFO + +#Suppression des règles précédentes +iptables -F +iptables -X + +######## +# DROP # +######## + +# Définition du blocage général +iptables -P INPUT DROP +iptables -P OUTPUT DROP +iptables -P FORWARD DROP + +# Drop des scans XMAS et NULL +iptables -A INPUT -p tcp --tcp-flags FIN,URG,PSH FIN,URG,PSH -j DROP +iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP +iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP +iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP + +########## +# ACCEPT # +########## + +# Conservations des connexions déjà établies +iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT +iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT + +# Autorisation du loopback (127.0.0.1) +iptables -A INPUT -i lo -j ACCEPT +iptables -A OUTPUT -o lo -j ACCEPT + +# Autorisation des échanges avec le serveur DNS (53) +iptables -A OUTPUT -p udp -m udp --dport 53 -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT +iptables -A INPUT -p udp -m udp --sport 53 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + +# NTP (123) +iptables -A INPUT -p udp --sport 123 -j ACCEPT +iptables -A OUTPUT -p udp --dport 123 -j ACCEPT + +# HTTP (80) +iptables -A INPUT -p tcp --dport 80 -j ACCEPT +iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT + +# HTTPS (443) +iptables -A INPUT -p tcp --dport 443 -j ACCEPT +iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT + +# SSH (7943) +iptables -A INPUT -p tcp --dport 7943 -j ACCEPT +iptables -A OUTPUT -p tcp --dport 7943 -j ACCEPT +iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT # ACCEPT SSH OUTPUT LIKE GIT + +# ICMP (Ping) +iptables -A INPUT -p icmp -j ACCEPT +iptables -A OUTPUT -p icmp -j ACCEPT + +# Parer les attaques de type Déni de Service +iptables -A FORWARD -p tcp --syn -m limit --limit 1/second -j ACCEPT +iptables -A FORWARD -p udp -m limit --limit 1/second -j ACCEPT +iptables -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/second -j ACCEPT + +# Parer les scans de ports +iptables -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT diff --git a/grafana.env b/grafana.env new file mode 100644 index 0000000..e6516d7 --- /dev/null +++ b/grafana.env @@ -0,0 +1,6 @@ +GF_AUTH_ANONYMOUS_ENABLED=true +GF_AUTH_BASIC_ENABLED=false +GF_AUTH_PROXY_ENABLED=false +GF_USERS_ALLOW_SIGN_UP=false +GF_INSTALL_PLUGINS=grafana-piechart-panel +GF_SERVER_ROOT_URL=%(protocol)s://%(domain)s:%(http_port)s/grafana \ No newline at end of file diff --git a/grafana/provisioning/dashboards/dashboard.yml b/grafana/provisioning/dashboards/dashboard.yml new file mode 100644 index 0000000..bc14030 --- /dev/null +++ b/grafana/provisioning/dashboards/dashboard.yml @@ -0,0 +1,21 @@ +apiVersion: 1 + +providers: + # provider name +- name: 'default' + # org id. will default to orgId 1 if not specified + orgId: 1 + # name of the dashboard folder. Required + folder: '' + # folder UID. will be automatically generated if not specified + folderUid: '' + # provider type. Required + type: file + # disable dashboard deletion + disableDeletion: false + # enable dashboard editing + editable: true + # how often Grafana will scan for changed dashboards + updateIntervalSeconds: 10 + options: + path: /etc/grafana/provisioning/dashboards \ No newline at end of file diff --git a/grafana/provisioning/dashboards/reverse-proxy_rev1.json b/grafana/provisioning/dashboards/reverse-proxy_rev1.json new file mode 100644 index 0000000..7abc943 --- /dev/null +++ b/grafana/provisioning/dashboards/reverse-proxy_rev1.json @@ -0,0 +1,1293 @@ +{ + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "6.3.6" + }, + { + "type": "panel", + "id": "grafana-piechart-panel", + "name": "Pie Chart", + "version": "1.3.9" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": 10906, + "graphTooltip": 0, + "id": null, + "iteration": 1569328089102, + "links": [ + { + "icon": "external link", + "tags": [ + "link" + ], + "type": "dashboards" + } + ], + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "s", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 0, + "y": 0 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "time() - process_start_time_seconds{job=\"$job\"}", + "format": "time_series", + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "", + "title": "Uptime", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(26, 206, 22, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 3, + "y": 0 + }, + "id": 26, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "200%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(increase(traefik_service_requests_total{code=\"404\",method=\"GET\",protocol=~\"$protocol\"}[$interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "metric": "traefik_requests_total", + "refId": "A", + "step": 60 + } + ], + "thresholds": "0,1", + "title": "404 Error Count last $interval", + "type": "singlestat", + "valueFontSize": "200%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "max" + }, + { + "aliasColors": {}, + "breakPoint": "50%", + "cacheTimeout": null, + "combine": { + "label": "Others", + "threshold": 0 + }, + "datasource": "Prometheus", + "fontSize": "80%", + "format": "short", + "gridPos": { + "h": 6, + "w": 7, + "x": 6, + "y": 0 + }, + "id": 18, + "interval": null, + "legend": { + "percentage": true, + "show": true, + "sort": null, + "sortDesc": null, + "values": true + }, + "legendType": "Right side", + "links": [], + "maxDataPoints": 3, + "nullPointMode": "connected", + "options": {}, + "pieType": "pie", + "strokeWidth": 1, + "targets": [ + { + "expr": "traefik_service_requests_total{protocol=~\"$protocol\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{method}} : {{code}}", + "refId": "A" + } + ], + "title": "$protocol return code", + "type": "grafana-piechart-panel", + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 13, + "y": 0 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(traefik_entrypoint_request_duration_seconds_sum) / sum(traefik_entrypoint_requests_total) * 1000", + "format": "time_series", + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "", + "title": "Average response time", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 7, + "x": 17, + "y": 0 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(traefik_service_request_duration_seconds_sum{protocol=~\"$protocol\"}) / sum(traefik_entrypoint_requests_total{protocol=~\"$protocol\"}) * 1000", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Average response time (ms)", + "refId": "A", + "step": 240 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average response time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 10, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 0, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 10, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(traefik_service_requests_total{code=\"404\",method=\"GET\",protocol=~\"$protocol\"}[$interval])) by (service)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{service}} ", + "refId": "A", + "step": 240 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bad Status Code Count $interval", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 6 + }, + "hideTimeOverride": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(traefik_service_requests_total[$interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total requests", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total requests over $interval", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 10, + "x": 0, + "y": 12 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{ instance }}", + "refId": "A", + "step": 240 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Used sockets", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 0, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 14, + "x": 10, + "y": 12 + }, + "id": 24, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(traefik_service_requests_total{protocol=~\"http|https\",code=\"200\"}[$interval])) by (service)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{service}} {{method}} {{code}}", + "refId": "A", + "step": 240 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Access to backends", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 7, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 30, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(traefik_entrypoint_open_connections) by (method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ method }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ENTRYPOINT - Open Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 7, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 28, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(traefik_service_open_connections) by (method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ method }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "BACKEND - Open Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 0, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 12, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/^[^234].*/", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(traefik_service_requests_total{protocol=~\"$protocol\"}[$interval])) by (code)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{code}}", + "refId": "A", + "step": 120 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Status Code Count per $interval", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 19, + "style": "dark", + "tags": [ + "traefik", + "load-balancer", + "docker", + "prometheus", + "link" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Job:", + "multi": false, + "name": "job", + "options": [], + "query": "label_values(job)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": "traefik", + "current": {}, + "datasource": "Prometheus", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Node:", + "multi": false, + "name": "node", + "options": [], + "query": "label_values(process_start_time_seconds, instance)", + "refresh": 1, + "regex": "/([^:]+):.*/", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "definition": "label_values(traefik_service_requests_total, protocol)", + "hide": 0, + "includeAll": true, + "label": "Service:", + "multi": true, + "name": "protocol", + "options": [], + "query": "label_values(traefik_service_requests_total, protocol)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": true, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "30m", + "value": "30m" + }, + "hide": 0, + "label": "Interval", + "name": "interval", + "options": [ + { + "selected": false, + "text": "auto", + "value": "$__auto_interval_interval" + }, + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": true, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "traefik", + "uid": "3ipsWfViz", + "version": 13, + "description": "Dashboard for Traefik2/Prometheus" +} \ No newline at end of file diff --git a/grafana/provisioning/datasources/datasource.yml b/grafana/provisioning/datasources/datasource.yml new file mode 100644 index 0000000..304d2f8 --- /dev/null +++ b/grafana/provisioning/datasources/datasource.yml @@ -0,0 +1,50 @@ +# config file version +apiVersion: 1 + +# list of datasources that should be deleted from the database +deleteDatasources: + - name: Prometheus + orgId: 1 + +# list of datasources to insert/update depending +# whats available in the database +datasources: + # name of the datasource. Required +- name: Prometheus + # datasource type. Required + type: prometheus + # access mode. direct or proxy. Required + access: proxy + # org id. will default to orgId 1 if not specified + orgId: 1 + # url + url: http://prometheus:9090 + # database password, if used + password: + # database user, if used + user: + # database name, if used + database: + # enable/disable basic auth + basicAuth: false + # basic auth username + basicAuthUser: + # basic auth password + basicAuthPassword: + # enable/disable with credentials headers + withCredentials: + # mark as default datasource. Max one per org + isDefault: true + # fields that will be converted to json and stored in json_data + jsonData: + graphiteVersion: "1.1" + tlsAuth: false + tlsAuthWithCACert: false + # json object of data that will be encrypted. + secureJsonData: + tlsCACert: "..." + tlsClientCert: "..." + tlsClientKey: "..." + version: 1 + # allow users to edit datasources from the UI. + editable: true diff --git a/init.sh b/init.sh new file mode 100755 index 0000000..1e798d1 --- /dev/null +++ b/init.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# Must be run as sudo + +cp ./firewall /etc/init.d/firewall +chmod +x /etc/init.d/firewall +update-rc.d firewall defaults diff --git a/prometheus/alert.rules b/prometheus/alert.rules new file mode 100644 index 0000000..e10abbe --- /dev/null +++ b/prometheus/alert.rules @@ -0,0 +1,11 @@ +groups: +- name: traefik + rules: + - alert: service_down + expr: up == 0 + for: 2m + labels: + severity: page + annotations: + summary: "Instance {{ $labels.instance }} down" + description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 2 minutes" \ No newline at end of file diff --git a/prometheus/prometheus.yml b/prometheus/prometheus.yml new file mode 100644 index 0000000..5da37c8 --- /dev/null +++ b/prometheus/prometheus.yml @@ -0,0 +1,12 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +rule_files: + - 'alert.rules' + +scrape_configs: + - job_name: 'traefik' + scrape_interval: 5s + static_configs: + - targets: ['traefik:8080'] diff --git a/whoami/docker-compose.yml b/whoami/docker-compose.yml new file mode 100644 index 0000000..d84a992 --- /dev/null +++ b/whoami/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3' + +services: + whoami: + image: "containous/whoami" + restart: always + container_name: "whoami" + networks: + - proxy + labels: + - "traefik.enable=true" + - "traefik.http.routers.whoami-secure.entrypoints=https" + - "traefik.http.routers.whoami-secure.rule=Host(`whoami.mrdev023.fr`)" + - "traefik.http.routers.whoami-secure.tls=true" + - "traefik.http.routers.whoami-secure.tls.certresolver=sslResolver" + # - "traefik.http.routers.whoami-secure.service=whoami" + # - "traefik.http.services.whoami.loadbalancer.server.port=9002" + - "traefik.docker.network=proxy" + +networks: + proxy: + external: true