├── .gitignore ├── LICENSE ├── README.md ├── roles ├── apt │ ├── files │ │ └── 99local │ └── tasks │ │ └── main.yml ├── certbot │ ├── files │ │ └── .gitkeep │ └── tasks │ │ └── main.yml ├── grafana │ ├── files │ │ ├── dashboard.yaml │ │ ├── grafana-dashboards │ │ │ └── .gitkeep │ │ ├── grafana.gpg │ │ ├── grafana.list │ │ └── nginx-grafana.conf │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── create_users.yml │ │ └── main.yml │ └── templates │ │ ├── datasource.yaml.j2 │ │ └── grafana.ini.j2 ├── influxdb │ ├── files │ │ ├── influxdata.gpg │ │ └── nginx-influxdb.conf │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── influxdata.list.j2 │ │ └── influxdb.conf.j2 ├── kapacitor │ ├── files │ │ └── influxdata.gpg │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── influxdata.list.j2 │ │ ├── kapacitor-handlers │ │ └── email.yaml.j2 │ │ ├── kapacitor-templates │ │ ├── available_memory.tick.j2 │ │ ├── cpu_usage.tick.j2 │ │ ├── deadman.tick.j2 │ │ ├── disk_usage.tick.j2 │ │ ├── failed_systemd_unit.tick.j2 │ │ ├── net_speed_test.tick.j2 │ │ ├── net_usage.tick.j2 │ │ ├── service_status.tick.j2 │ │ └── tls_expiry.tick.j2 │ │ ├── kapacitor.conf.j2 │ │ └── nginx-kapacitor.conf.j2 ├── monitor │ ├── files │ │ ├── exec-scripts │ │ │ └── .gitkeep │ │ ├── influxdata.gpg │ │ ├── systemd-smart.conf │ │ ├── systemd-wireguard.conf │ │ └── telegraf.conf │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ ├── kapacitor.yml │ │ ├── main.yml │ │ └── telegraf.yml │ └── templates │ │ ├── create_task.json.j2 │ │ ├── influxdata.list.j2 │ │ ├── patch_task.json.j2 │ │ ├── plugins │ │ ├── input │ │ │ ├── cpu.conf.j2 │ │ │ ├── disk.conf.j2 │ │ │ ├── diskio.conf.j2 │ │ │ ├── dns_query.conf.j2 │ │ │ ├── exec.conf.j2 │ │ │ ├── kernel.conf.j2 │ │ │ ├── mem.conf.j2 │ │ │ ├── net.conf.j2 │ │ │ ├── processes.conf.j2 │ │ │ ├── smart.conf.j2 │ │ │ ├── system.conf.j2 │ │ │ ├── systemd_units.conf.j2 │ │ │ ├── temp.conf.j2 │ │ │ ├── wireguard.conf.j2 │ │ │ └── x509_cert.conf.j2 │ │ └── output │ │ │ └── influxdb.conf.j2 │ │ └── sudoers-smart.j2 ├── networking │ ├── tasks │ │ └── main.yml │ └── templates │ │ └── wired.network.j2 ├── nftables │ ├── files │ │ ├── nft-conntrack.conf │ │ ├── nft-default.conf │ │ ├── nft-geo-filter.timer │ │ └── nftables.conf │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ └── nft-geo-filter.service.j2 ├── nginx-base │ ├── files │ │ ├── index.default.html │ │ └── nft-nginx.conf │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ └── default.j2 ├── nginx │ ├── files │ │ └── index.default.html │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ └── ssl-template.j2 ├── openvpn │ ├── files │ │ └── secret │ │ │ └── .gitkeep │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── nft-openvpn.conf.j2 │ │ └── server.conf.j2 ├── postfix │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── aliases.j2 │ │ └── main.cf.j2 ├── rsyslog │ ├── files │ │ └── rsyslog.conf │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ └── nft-rsyslog.conf.j2 ├── system-config │ ├── files │ │ ├── journal-override.conf │ │ ├── sudoers │ │ └── system-override.conf │ ├── handlers │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── unattended-upgrades │ ├── files │ │ ├── 20auto-upgrades │ │ ├── Debian │ │ ├── Ubuntu │ │ └── listchanges.conf │ └── tasks │ │ └── main.yml ├── user-config │ └── .gitkeep ├── wireguard │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── iperf3.service.j2 │ │ ├── nft-wireguard-peer-server-network.conf.j2 │ │ ├── nft-wireguard.conf.j2 │ │ ├── wireguard-peer-server.netdev.j2 │ │ ├── wireguard-peer-server.network.j2 │ │ ├── wireguard.netdev.j2 │ │ └── wireguard.network.j2 └── znc │ ├── defaults │ └── main.yml │ ├── files │ └── znc.service │ ├── handlers │ └── main.yml │ ├── meta │ └── main.yml │ ├── tasks │ ├── main.yml │ ├── ssl.yml │ └── znc-modules │ │ ├── adminlog.yml │ │ └── sasl.yml │ └── templates │ ├── nft-znc.conf.j2 │ ├── znc-deploy.sh.j2 │ └── znc.conf.j2 ├── site.yml └── vars.sample.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .vault_password 2 | ansible.cfg 3 | inventory 4 | vars.yml 5 | roles/openvpn/files/secret/* 6 | !roles/openvpn/files/secret/.gitkeep 7 | roles/user-config/* 8 | !roles/user-config/.gitkeep 9 | roles/certbot/files/* 10 | !roles/certbot/files/.gitkeep 11 | roles/monitor/files/exec-scripts/* 12 | !roles/monitor/files/exec-scripts/.gitkeep 13 | roles/grafana/files/grafana-dashboards/* 14 | !roles/grafana/files/grafana-dashboards/.gitkeep 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ansible-server-debian 2 | Ansible Playbook to deploy a Debian Server 3 | 4 | This playbook was initially created to easily set up a VPN server within minutes. I've added a few more roles to this playbook since then. You can modify your site.yml file and select the roles which suit your needs. 5 | 6 | This playbook currently includes the following roles: 7 | - **apt**: Install core packages 8 | - **system-config**: Set up core config files in /etc 9 | - **networking**: Configure systemd-networkd and enabling IP forwarding 10 | - **nftables**: Set up a basic nftables ruleset and allow other roles to create firewall rules. 11 | - **unattended-upgrades**: Automate security upgrades 12 | - **postfix**: Set up a send-only Postfix SMTP server to receive notifications from the server 13 | - **openvpn**: Set up the OpenVPN server and configure firewall rules 14 | - **rsyslog**: Set up a remote syslog server 15 | - **user-config**: Local user configurations. This role has beek kept empty for you to fill it with your user configurations. 16 | - **nginx**: Setup an HTTPS server block for a given hostname. This role will call the certbot role to generate a TLS cert. 17 | - **nginx-base**: Setup a default HTTP and HTTPS server using the server's FQDN. This role should NEVER be called. Use the nginx role instead. 18 | - **znc**: Setup an IRC bounder via ZNC 19 | - **wireguard**: Setup a WireGuard VPN server 20 | - **certbot**: Generate a TLS cert for the given hostname. Only uses the DNS-01 challenege for domain verification. 21 | - **influxdb**: Set up a time series database using InfluxDB 22 | - **kapacitor**: Set up data processing and alert generation using Kapacitor. Kapacitor gets its data from an InfluxDB server. 23 | - **monitor**: Set up Telegraf to gather data from a host and send it to an InfluxDB server and set up alerting tasks on a remote Kapacitor server. 24 | - **grafana**: Set up a Grafana server to create dashboards and view the time series data stored on an InfluxDB server 25 | 26 | # Configure the playbook 27 | Before you use this playbook, you'll need to do 2 things 28 | 29 | ## Creating vars.yml 30 | To keep this playbook as generic as possible, I've moved all the variables into a separate file called vars.yml. You will have to create this file by copying `vars.sample.yml` to `vars.yml` and adding the required information. You can also encrypt `vars.yml` using ansible-vault if you so desire. 31 | 32 | ## Add OpenVPN related files 33 | You will need to add the following files to the OpenVPN role's files directory (roles/openvpn/files). Make sure the files names are the same as given below: 34 | 35 | - ca.crt: Your root certificate (CA file) 36 | - crl.pem: Certicate Revocation List 37 | - dh.pem: Diffie Hellman parameters 38 | - server.crt: Your server's certificate (signed by your CA) 39 | - server.key: Your server's private key 40 | - ta.key: OpenVPN static key required for HMAC authentication 41 | 42 | All these files can be easily generated using [EasyRSA](https://github.com/OpenVPN/easy-rsa). Check out the Arch Wiki to learn [how to use EasyRSA](https://wiki.archlinux.org/index.php/Easy-RSA). 43 | 44 | # Instructions 45 | 1. Make sure your SSH public key has been deployed to the root account as the playbook is using root as the `remote_user`. If you'd rather SSH into your own account and use sudo to run the playbook, then you'll have to replace `remote_user` with `become_user` in site.yml 46 | 2. Make sure **python-netaddr** is installed on your system, as some of the roles in this playbook use the `ipaddr` filter which needs that package. 47 | 3. Edit the inventory (`/etc/ansible/hosts` or a custom inventory file) to add your Debian server's IP or hostname 48 | 4. Change the hosts entry in `site.yml` to your Debian server's IP or hostname 49 | 5. Modify the list of roles provided in `site.yml` according to your requirements. 50 | 6. Run the playbook using `ansible-playbook site.yml` 51 | 52 | To run only a section of the configuration, make use of the --tags flag. Eg:- `ansible-playbook site.yml --tags rsyslog` 53 | -------------------------------------------------------------------------------- /roles/apt/files/99local: -------------------------------------------------------------------------------- 1 | APT::Install-Recommends "0"; 2 | APT::Install-Suggests "0"; 3 | -------------------------------------------------------------------------------- /roles/apt/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install required packages on the host 3 | 4 | - name: "Disable all apt recommendations and suggestions" 5 | copy: 6 | src: "99local" 7 | dest: "/etc/apt/apt.conf.d/99local" 8 | owner: root 9 | group: root 10 | mode: 0644 11 | 12 | - name: "Uninstall rsyslog" 13 | apt: {name: "rsyslog", state: absent, purge: yes, autoremove: yes} 14 | when: remove_rsyslog|d(false) 15 | 16 | - name: "Remove unneeded Ubuntu packages" 17 | apt: 18 | name: 19 | - "accountsservice" 20 | - "byobu" 21 | - "fwupd" 22 | - "libfwupd2" 23 | - "haveged" 24 | - "lvm2" 25 | - "mdadm" 26 | - "multipath-tools" 27 | - "packagekit" 28 | - "plymouth" 29 | - "snapd" 30 | - "ufw" 31 | state: absent 32 | purge: yes 33 | autoremove: yes 34 | when: ansible_facts['distribution'] == "Ubuntu" 35 | 36 | - name: "Upgrade the system" 37 | apt: 38 | update_cache: yes 39 | upgrade: dist 40 | 41 | - name: "Install sudo" 42 | apt: {name: "sudo", state: present} 43 | 44 | - name: "Install zsh and shell completions" 45 | apt: 46 | name: ["zsh", "bash-completion"] 47 | state: present 48 | 49 | - name: "Install man pages" 50 | apt: 51 | name: ["man-db", "manpages"] 52 | state: present 53 | 54 | - name: "Install vim" 55 | apt: {name: "vim", state: present} 56 | 57 | - name: "Install misc tools" 58 | apt: 59 | name: ["tree", "htop", "git", "ansible", "tcpdump", "tmux"] 60 | state: present 61 | ... 62 | -------------------------------------------------------------------------------- /roles/certbot/files/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpthms/ansible-debian-server/0c6ba352dbbf0bc0298c24f697cab1a44f70d9ba/roles/certbot/files/.gitkeep -------------------------------------------------------------------------------- /roles/certbot/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Tasks to obtain a TLS certificate from Let's Encrypt 3 | 4 | - name: "Install Certbot and the DNS plugin" 5 | apt: 6 | name: ["certbot", "{{ certbot_dns_plugin.package }}"] 7 | state: present 8 | 9 | - name: "Copy the DNS plugin credentials" 10 | copy: 11 | src: "dns-creds" 12 | dest: "/etc/letsencrypt/.dns-creds" 13 | owner: root 14 | group: root 15 | mode: 0400 16 | 17 | - name: "Generate the Let's Encrypt TLS certificate" 18 | command: 19 | cmd: >- 20 | /usr/bin/certbot 21 | certonly 22 | --non-interactive 23 | --agree-tos 24 | --email 25 | {{ user_email }} 26 | --domain 27 | {{ tls_domain }} 28 | {{ certbot_dns_plugin.arg_name }} 29 | {{ certbot_dns_propagation.arg_name }} 30 | {{ certbot_dns_propagation.value }} 31 | {{ certbot_dns_credentials.arg_name }} 32 | /etc/letsencrypt/.dns-creds 33 | creates: "/etc/letsencrypt/live/{{ tls_domain }}/fullchain.pem" 34 | ... 35 | -------------------------------------------------------------------------------- /roles/grafana/files/dashboard.yaml: -------------------------------------------------------------------------------- 1 | # config file version 2 | apiVersion: 1 3 | 4 | providers: 5 | # an unique provider name. Required 6 | - name: Monitoring 7 | # Org id. Default to 1 8 | orgId: 1 9 | # name of the dashboard folder. 10 | folder: Monitoring 11 | # folder UID. will be automatically generated if not specified 12 | folderUid: '' 13 | # provider type. Default to 'file' 14 | type: file 15 | # disable dashboard deletion 16 | disableDeletion: false 17 | # enable dashboard editing 18 | editable: true 19 | # how often Grafana will scan for changed dashboards 20 | updateIntervalSeconds: 10 21 | # allow updating provisioned dashboards from the UI 22 | allowUiUpdates: true 23 | options: 24 | # path to dashboard files on disk. Required when using the 'file' type 25 | path: /etc/grafana/dashboards 26 | # use folder names from filesystem to create folders in Grafana 27 | foldersFromFilesStructure: false 28 | -------------------------------------------------------------------------------- /roles/grafana/files/grafana-dashboards/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpthms/ansible-debian-server/0c6ba352dbbf0bc0298c24f697cab1a44f70d9ba/roles/grafana/files/grafana-dashboards/.gitkeep -------------------------------------------------------------------------------- /roles/grafana/files/grafana.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpthms/ansible-debian-server/0c6ba352dbbf0bc0298c24f697cab1a44f70d9ba/roles/grafana/files/grafana.gpg -------------------------------------------------------------------------------- /roles/grafana/files/grafana.list: -------------------------------------------------------------------------------- 1 | # Grafana repository 2 | deb [signed-by=/usr/share/keyrings/grafana.gpg] https://packages.grafana.com/oss/deb stable main 3 | -------------------------------------------------------------------------------- /roles/grafana/files/nginx-grafana.conf: -------------------------------------------------------------------------------- 1 | location /grafana/ { 2 | proxy_http_version 1.1; 3 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 4 | proxy_set_header Host $host; 5 | proxy_pass http://127.0.0.1:3000/; 6 | } 7 | 8 | location /grafana/public { 9 | alias /usr/share/grafana/public; 10 | try_files $uri =404; 11 | } 12 | -------------------------------------------------------------------------------- /roles/grafana/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Handlers for Grafana 3 | 4 | - name: "Restart Grafana" 5 | systemd: 6 | name: "grafana-server" 7 | state: restarted 8 | ... 9 | -------------------------------------------------------------------------------- /roles/grafana/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Role dependencies for Grafana 3 | 4 | dependencies: 5 | - role: "nginx" 6 | vars: 7 | nginx_server_name: "{{ grafana.url | urlsplit('hostname') }}" 8 | when: grafana.use_tls | d(false) | bool 9 | ... 10 | -------------------------------------------------------------------------------- /roles/grafana/tasks/create_users.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create users in Grafana 3 | 4 | - name: "Check if the user already exists in Grafana's database" 5 | uri: 6 | url: "{{ grafana.url ~ '/api/users/lookup?loginOrEmail=' ~ item.username }}" 7 | url_username: "{{ grafana.admin_username }}" 8 | url_password: "{{ grafana.admin_password }}" 9 | force_basic_auth: true 10 | status_code: 11 | - 200 12 | - 404 13 | register: grafana_user_status 14 | 15 | - name: "Create the Grafana user" 16 | block: 17 | 18 | - name: "Add the Grafana user to Grafana's database" 19 | uri: 20 | url: "{{ grafana.url ~ '/api/admin/users' }}" 21 | url_username: "{{ grafana.admin_username }}" 22 | url_password: "{{ grafana.admin_password }}" 23 | method: POST 24 | force_basic_auth: true 25 | body_format: json 26 | body: >- 27 | { 28 | "name": "{{ item.username }}", 29 | "login": "{{ item.username }}", 30 | "password": "{{ item.password }}" 31 | } 32 | no_log: yes 33 | register: grafana_user_result 34 | 35 | - name: "Set the Grafana user's organization role" 36 | uri: 37 | url: "{{ grafana.url ~ '/api/org/users/' ~ grafana_user_result.json.id }}" 38 | url_username: "{{ grafana.admin_username }}" 39 | url_password: "{{ grafana.admin_password }}" 40 | method: PATCH 41 | force_basic_auth: true 42 | body_format: json 43 | body: >- 44 | { 45 | "role": "{{ 'Editor' if (item.is_editor | d(false) | bool) else 'Viewer' }}" 46 | } 47 | 48 | when: grafana_user_status.status == 404 49 | 50 | - name: "Patch the Grafana user's organization role" 51 | uri: 52 | url: "{{ grafana.url ~ '/api/org/users/' ~ grafana_user_status.json.id }}" 53 | url_username: "{{ grafana.admin_username }}" 54 | url_password: "{{ grafana.admin_password }}" 55 | method: PATCH 56 | force_basic_auth: true 57 | body_format: json 58 | body: >- 59 | { 60 | "role": "{{ 'Editor' if (item.is_editor | d(false) | bool) else 'Viewer' }}" 61 | } 62 | when: grafana_user_status.status == 200 63 | -------------------------------------------------------------------------------- /roles/grafana/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Role to install and configure a Grafana server 3 | 4 | - name: "Add the Grafana repo" 5 | copy: 6 | src: "grafana.list" 7 | dest: "/etc/apt/sources.list.d/grafana.list" 8 | owner: root 9 | group: root 10 | mode: 0644 11 | 12 | - name: "Add Grafana's GPG key to apt's keyring" 13 | copy: 14 | src: "grafana.gpg" 15 | dest: "/usr/share/keyrings/grafana.gpg" 16 | owner: root 17 | group: root 18 | mode: 0644 19 | 20 | - name: "Install Grafana" 21 | apt: 22 | name: "grafana" 23 | update_cache: yes 24 | state: present 25 | 26 | - name: "Copy Grafana's config file" 27 | template: 28 | src: "grafana.ini.j2" 29 | dest: "/etc/grafana/grafana.ini" 30 | owner: root 31 | group: grafana 32 | mode: 0640 33 | register: grafana_conf_result 34 | 35 | - name: "Setup TLS for Grafana" 36 | block: 37 | 38 | - name: "Add an nginx location block to proxy_pass to Grafana" 39 | copy: 40 | src: "nginx-grafana.conf" 41 | dest: "/etc/nginx/server-conf/{{ grafana.url | urlsplit('hostname') }}/location/grafana.conf" 42 | owner: root 43 | group: root 44 | mode: 0644 45 | register: nginx_grafana_config 46 | 47 | - name: "Reload nginx if the nginx Grafana config has changed" 48 | systemd: 49 | name: "nginx" 50 | state: "reloaded" 51 | when: nginx_grafana_config is changed 52 | 53 | when: grafana.use_tls | d(false) | bool 54 | 55 | - name: "Enable and start the Grafana server" 56 | systemd: 57 | name: "grafana-server" 58 | daemon_reload: yes 59 | enabled: yes 60 | state: started 61 | register: grafana_first_start 62 | 63 | - name: "Restart the Grafana server if the config file has changed" 64 | systemd: 65 | name: "grafana-server" 66 | state: restarted 67 | when: 68 | - grafana_conf_result is changed 69 | - grafana_first_start is not changed 70 | 71 | - name: "Change the Grafana admin password" 72 | uri: 73 | url: "{{ grafana.url ~ '/api/user/password' }}" 74 | url_username: "{{ grafana.admin_username }}" 75 | url_password: "admin" 76 | method: PUT 77 | force_basic_auth: true 78 | status_code: 79 | - 200 80 | - 401 81 | body_format: json 82 | body: >- 83 | { 84 | "oldPassword": "admin", 85 | "newPassword": "{{ grafana.admin_password }}" 86 | } 87 | no_log: true 88 | 89 | - name: "Create Grafana users" 90 | include_tasks: 91 | file: "create_users.yml" 92 | loop: "{{ grafana.users }}" 93 | 94 | - name: "Create the Grafana provisioning directories" 95 | file: 96 | path: "{{ item }}" 97 | state: directory 98 | owner: "root" 99 | group: "grafana" 100 | mode: 0755 101 | loop: 102 | - "/etc/grafana/provisioning/datasources" 103 | - "/etc/grafana/provisioning/dashboards" 104 | 105 | - name: "Create the Grafana dashboard directory" 106 | file: 107 | path: "/etc/grafana/dashboards" 108 | state: directory 109 | owner: "root" 110 | group: "grafana" 111 | mode: 0755 112 | 113 | - name: "Copy the dashboard JSON files" 114 | copy: 115 | src: "grafana-dashboards/" 116 | dest: "/etc/grafana/dashboards" 117 | owner: "root" 118 | group: "grafana" 119 | mode: 0640 120 | changed_when: false 121 | 122 | - name: "Get a list of the dashboard JSON files" 123 | find: 124 | paths: "/etc/grafana/dashboards" 125 | register: "dashboard_list" 126 | 127 | - name: "Use the specified data source in the dashboard JSON files" 128 | replace: 129 | path: "{{ item.path }}" 130 | regexp: '"(?:\${)?DS_[A-Z0-9_-]+(?:})?"' 131 | replace: '"{{ grafana.datasource.name }}"' 132 | changed_when: false 133 | loop: "{{ dashboard_list.files }}" 134 | 135 | - name: "Add the datasource provisioning config file" 136 | template: 137 | src: "datasource.yaml.j2" 138 | dest: "/etc/grafana/provisioning/datasources/datasource.yaml" 139 | owner: "root" 140 | group: "grafana" 141 | mode: 0640 142 | notify: 143 | - "Restart Grafana" 144 | 145 | - name: "Add the dashboard provisioning config file" 146 | copy: 147 | src: "dashboard.yaml" 148 | dest: "/etc/grafana/provisioning/dashboards/dashboard.yaml" 149 | owner: "root" 150 | group: "grafana" 151 | mode: 0640 152 | notify: 153 | - "Restart Grafana" 154 | ... 155 | -------------------------------------------------------------------------------- /roles/grafana/templates/datasource.yaml.j2: -------------------------------------------------------------------------------- 1 | # config file version 2 | apiVersion: 1 3 | 4 | # list of datasources to insert/update depending 5 | # what's available in the database 6 | datasources: 7 | # name of the datasource. Required 8 | - name: {{ grafana.datasource.name }} 9 | # datasource type. Required 10 | type: {{ grafana.datasource.type }} 11 | # access mode. proxy or direct (Server or Browser in the UI). Required 12 | access: proxy 13 | # org id. will default to orgId 1 if not specified 14 | orgId: 1 15 | # url 16 | url: {{ grafana.datasource.url }} 17 | # database name, if used 18 | database: {{ grafana.datasource.database_name }} 19 | # enable/disable basic auth 20 | basicAuth: {{ 'true' if grafana.datasource.basic_auth is defined else 'false' }} 21 | # basic auth username 22 | basicAuthUser: {{ grafana.datasource.basic_auth.username if grafana.datasource.basic_auth is defined }} 23 | # mark as default datasource. Max one per org 24 | isDefault: true 25 | {% if grafana.datasource.json_data is defined %} 26 | # fields that will be converted to json and stored in jsonData 27 | jsonData: 28 | {% for item in (grafana.datasource.json_data | dict2items) %} 29 | {{ item.key }}: {{ item.value }} 30 | {% endfor %} 31 | {% endif %} 32 | # json object of data that will be encrypted. 33 | secureJsonData: 34 | # basic auth password 35 | basicAuthPassword: {{ grafana.datasource.basic_auth.password if grafana.datasource.basic_auth is defined }} 36 | version: 1 37 | # allow users to edit datasources from the UI. 38 | editable: false 39 | -------------------------------------------------------------------------------- /roles/grafana/templates/grafana.ini.j2: -------------------------------------------------------------------------------- 1 | #################################### Paths #################################### 2 | [paths] 3 | # Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used) 4 | data = /var/lib/grafana 5 | 6 | # Temporary files in `data` directory older than given duration will be removed 7 | temp_data_lifetime = 24h 8 | 9 | # Directory where grafana will automatically scan and look for plugins 10 | plugins = /var/lib/grafana/plugins 11 | 12 | # folder that contains provisioning config files that grafana will apply on startup and while running. 13 | provisioning = /etc/grafana/provisioning 14 | 15 | #################################### Server #################################### 16 | [server] 17 | # Protocol (http, https, h2, socket) 18 | protocol = http 19 | 20 | # The ip address to bind to, empty will bind to all interfaces 21 | http_addr = {{ '127.0.0.1' if (grafana.use_tls | d(false) | bool) }} 22 | 23 | # The http port to use 24 | http_port = 3000 25 | 26 | # The public facing domain name used to access grafana from a browser 27 | domain = {{ grafana.url | urlsplit('hostname') }} 28 | 29 | # Redirect to correct domain if host header does not match domain 30 | # Prevents DNS rebinding attacks 31 | enforce_domain = true 32 | 33 | # The full public facing url you use in browser, used for redirects and emails 34 | # If you use reverse proxy and sub path specify full url (with sub path) 35 | root_url = {{ grafana.url }} 36 | 37 | # Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons. 38 | serve_from_sub_path = false 39 | 40 | # Log web requests 41 | router_logging = false 42 | 43 | # the path relative working path 44 | static_root_path = public 45 | 46 | # enable gzip 47 | enable_gzip = false 48 | 49 | #################################### Database #################################### 50 | [database] 51 | # You can configure the database connection by specifying type, host, name, user and password 52 | # as separate properties or as on string using the url properties. 53 | 54 | # Either "mysql", "postgres" or "sqlite3", it's your choice 55 | type = sqlite3 56 | name = grafana 57 | 58 | # For "sqlite3" only, path relative to data_path setting 59 | path = grafana.db 60 | 61 | # Max idle conn setting default is 2 62 | max_idle_conn = 2 63 | 64 | # Max conn setting default is 0 (mean not set) 65 | max_open_conn = 66 | 67 | # Connection Max Lifetime default is 14400 (means 14400 seconds or 4 hours) 68 | conn_max_lifetime = 14400 69 | 70 | # Set to true to log the sql calls and execution times. 71 | log_queries = 72 | 73 | # For "sqlite3" only. cache mode setting used for connecting to the database. (private, shared) 74 | cache_mode = private 75 | 76 | #################################### Data proxy ########################### 77 | [dataproxy] 78 | 79 | # This enables data proxy logging, default is false 80 | logging = false 81 | 82 | # How long the data proxy waits before timing out, default is 30 seconds. 83 | # This setting also applies to core backend HTTP data sources where query requests use an HTTP client with timeout set. 84 | timeout = 30 85 | 86 | # If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request, default is false. 87 | send_user_header = false 88 | 89 | #################################### Security #################################### 90 | [security] 91 | # disable creation of admin user on first start of grafana 92 | disable_initial_admin_creation = false 93 | 94 | # default admin user, created on startup 95 | admin_user = {{ grafana.admin_username }} 96 | 97 | # default admin password, can be changed before first start of grafana, or in profile settings 98 | admin_password = admin 99 | 100 | # used for signing 101 | secret_key = {{ grafana.secret_key }} 102 | 103 | # data source proxy whitelist (ip_or_domain:port separated by spaces) 104 | data_source_proxy_whitelist = {% for item in (grafana.data_source_proxy_whitelist | d([])) %}{{ item }} {% endfor %} 105 | 106 | 107 | # disable protection against brute force login attempts 108 | disable_brute_force_login_protection = false 109 | 110 | # set to true if you host Grafana behind HTTPS. default is false. 111 | cookie_secure = {{ 'true' if (grafana.use_tls | d(false) | bool) else 'false' }} 112 | 113 | # set cookie SameSite attribute. defaults to `lax`. can be set to "lax", "strict", "none" and "disabled" 114 | cookie_samesite = lax 115 | 116 | # set to true if you want to allow browsers to render Grafana in a ,