diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..0af4985 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,72 @@ +--- +# .ansible-lint +# exclude_paths included in this file are parsed relative to this file's location +# and not relative to the CWD of execution. CLI arguments passed to the --exclude +# option will be parsed relative to the CWD of execution. +exclude_paths: + - .cache/ # implicit unless exclude_paths is defined in config + - .github/ + - roles/monitoring/files/alerts.d/ +# parseable: true +# quiet: true +# verbosity: 1 + +# Mock modules or roles in order to pass ansible-playbook --syntax-check +mock_modules: + - zuul_return + # note the foo.bar is invalid as being neither a module or a collection + - fake_namespace.fake_collection.fake_module + - fake_namespace.fake_collection.fake_module.fake_submodule +mock_roles: + - mocked_role + - author.role_name # old standalone galaxy role + - fake_namespace.fake_collection.fake_role # role within a collection + +# Enable checking of loop variable prefixes in roles +loop_var_prefix: "{role}_" + +# Enforce variable names to follow pattern below, in addition to Ansible own +# requirements, like avoiding python identifiers. To disable add `var-naming` +# to skip_list. +# var_naming_pattern: "^[a-z_][a-z0-9_]*$" + +use_default_rules: true +# Load custom rules from this specific folder +# rulesdir: +# - ./rule/directory/ + +# This makes linter to fully ignore rules/tags listed below +skip_list: + - fqcn-builtins + +# This makes the linter display but not fail for rules/tags listed below: +warn_list: + - package-latest + - experimental # experimental is included in the implicit list + # - role-name + +# Offline mode disables installation of requirements.yml +offline: false + +# Define required Ansible's variables to satisfy syntax check +extra_vars: + foo: bar + multiline_string_variable: | + line1 + line2 + complex_variable: ":{;\t$()" + +# Uncomment to enforce action validation with tasks, usually is not +# needed as Ansible syntax check also covers it. +# skip_action_validation: false + +# List of additional kind:pattern to be added at the top of the default +# match list, first match determines the file kind. +kinds: + # - playbook: "**/examples/*.{yml,yaml}" + # - galaxy: "**/folder/galaxy.yml" + # - tasks: "**/tasks/*.yml" + # - vars: "**/vars/*.yml" + # - meta: "**/meta/main.yml" + - yaml: "**/*.yaml" + - yml: "**/*.yml" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82f73c1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# ---> Ansible +*.retry +*.swp + +# ignore dev/test playbooks +dev*.yml +test*.yml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..080406e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,8 @@ +repos: + - repo: https://github.com/ansible-community/ansible-lint.git + rev: v6.8.0 # put latest release tag from https://github.com/ansible-community/ansible-lint/releases/ + hooks: + - id: ansible-lint + name: Ansible-lint + description: This hook runs ansible-lint. + entry: ansible-lint --nocolor diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..d49c035 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,6 @@ +[defaults] +inventory = ./inventory/hcloud.yml +host_key_checking = False +vault_identity_list = dtsv-dev@~/.vault_pass_dtsv +vault_password_file = ~/.vault_pass_dtsv +remote_user = oli diff --git a/db.yml b/db.yml new file mode 100644 index 0000000..b8c4968 --- /dev/null +++ b/db.yml @@ -0,0 +1,6 @@ +--- +- name: Install PostgreSQL Server + hosts: DB + roles: + - postgresql + become: true diff --git a/group_vars/all.yml b/group_vars/all.yml new file mode 100644 index 0000000..2ea2793 --- /dev/null +++ b/group_vars/all.yml @@ -0,0 +1,65 @@ +--- +# Hetzner Cloud API Tokens +vault_hcloud_token: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 34663466303439366438333433393130326337383265643332316333336331306461303330356131 + 3965396464356466373466313037306638396130633130370a643639363964636630633062333261 + 66653764326538393934396537626463356162376661333635663563303465633537343030353435 + 3533646561663736390a613666643565313838343636646265373735386464613533306437326261 + 32616235396138306335373466303337666330383633666663653162613736386132383132346333 + 32613539313165366363363633356463356539363561396365626435343139336266656362313536 + 63386239383362636231633138333136383339336662623331393530613034663664663164353364 + 34636138383365633862 +vault_hcloud_token_terraform: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 32613339373964636635323439396465313732393463643134306635653532346665363630386135 + 6130353538326163663462666538623962346362323930330a303331373835663861323335656532 + 36386464373464353436613738326530653433303435363730323534363565386366396132333034 + 6139613632363464310a326234666230653638653736343562346565663661326161313565643433 + 30616632336538633436396631656563356264303662383361633161623766303364656236386366 + 30623065323661346135613334383465613037663133636239363362363162313966393730353765 + 30353633353231633065333439326264303135616365373461623033663262333965643237366534 + 61323365373231626337 +vault_ionos_token_terraform: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 30653231383361616437346262386365353031613265333238323866313033666336343863353539 + 6436653932633965316537643035666636663263396633610a333738663861336530393361383764 + 33306335643537366532613964353233653731656130393866633030663961383266643762336131 + 3436363963326135340a353435303235666534656561613664623734336639333461616262656165 + 65333665386631373936333962316135323564623632373230326635643934666461616234306664 + 65353431626465366262396261396135333730393663353462376234633666326335376136643635 + 32333737346566613366336436376634396435313566613061666261353639646633623638346565 + 65346263646233316333363364323936393136353230616164663966313365643034653139363963 + 65613064303732303331376332316439613436326262323161626537353064643037316162376466 + 6336623739613764323634653530653838643236653161363365 +vault_ionos_token_dns: "{{ vault_ionos_token_terraform }}" + +# Github API Tokens +vault_github_token: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 37373731613762353062373434323764376264303962633738353632363336313136363536346432 + 3736356364333433353562313438643934383966336463340a663463316365326565333736616336 + 62393866633932373930613733653362663430633765663066376631303938666466653163653337 + 3338313136666561370a353038323833376137343833633262343836333362306561383533393933 + 34343235333262643065656633373838373332613533306235363762643137326435383234306665 + 3337353232626232393963636134343262633162643365323530 + +# Central Infrastructure +reverse_proxy_ip: "10.0.0.2" +nextcloud_server_ip: "{{ reverse_proxy_ip }}" +pgsql_server_ip: "10.0.0.3" +pgsql_server_port: 5432 +smtp_hostname: "smtp.ionos.de" +smtp_port: 465 +turn_server: "turn.ows.cx" +turn_port: 443 +vault_turn_secret: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 39663864666566643137323531656335363534643732373039613665336265393836306363326230 + 3862316566393262626334336238623835396363663831640a303432386338396131636135353665 + 31623762363463386131333565643338663962636530336661663637333963623865313133376561 + 6465333634323832390a623362626666616663336565643765653763626666663164623366303237 + 65316238323838646263626431326533353566343935643931313063393830616134386539383162 + 35616666303234636630383362356438613539343738616437353230623635363535393365386231 + 63356461356232643863653035303937356661393162376537663363393132643435326666303335 + 64633636376433323037 diff --git a/group_vars/hcloud.yml b/group_vars/hcloud.yml new file mode 100644 index 0000000..252c14d --- /dev/null +++ b/group_vars/hcloud.yml @@ -0,0 +1,7 @@ +--- +# Hetzner Cloud Node Variables +deb_architecture: "amd64" +# Main User from Terraform cloud-init +main_user: oli +# SSH Private Key +ansible_ssh_private_key_file: "~/.ssh/dtsv_ed25519" diff --git a/host_vars/localhost.yml b/host_vars/localhost.yml new file mode 100644 index 0000000..47c93e4 --- /dev/null +++ b/host_vars/localhost.yml @@ -0,0 +1,3 @@ +--- +deb_architecture: "amd64" +main_user: oli diff --git a/inventory/hcloud.yml b/inventory/hcloud.yml new file mode 100644 index 0000000..8c07790 --- /dev/null +++ b/inventory/hcloud.yml @@ -0,0 +1,21 @@ +plugin: hcloud +token: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 34663466303439366438333433393130326337383265643332316333336331306461303330356131 + 3965396464356466373466313037306638396130633130370a643639363964636630633062333261 + 66653764326538393934396537626463356162376661333635663563303465633537343030353435 + 3533646561663736390a613666643565313838343636646265373735386464613533306437326261 + 32616235396138306335373466303337666330383633666663653162613736386132383132346333 + 32613539313165366363363633356463356539363561396365626435343139336266656362313536 + 63386239383362636231633138333136383339336662623331393530613034663664663164353364 + 34636138383365633862 +connect_with: public_ipv4 + +# Group by a location with prefix e.g. "hcloud_location_nbg1" +# and image_os_flavor without prefix and separator e.g. "ubuntu" +# and status with prefix e.g. "server_status_running" +keyed_groups: + - key: labels + prefix: label + - key: status + prefix: server_status diff --git a/localhost.yml b/localhost.yml new file mode 100644 index 0000000..3a4402f --- /dev/null +++ b/localhost.yml @@ -0,0 +1,6 @@ +--- +- name: Install bastion host + hosts: localhost + roles: + - bastion + become: true diff --git a/roles/bastion/files/ssh/dtsv_ed25519 b/roles/bastion/files/ssh/dtsv_ed25519 new file mode 100644 index 0000000..3e37981 --- /dev/null +++ b/roles/bastion/files/ssh/dtsv_ed25519 @@ -0,0 +1,25 @@ +$ANSIBLE_VAULT;1.2;AES256;dtsv-dev +61613262653734376165353363343366363661616561636563306430613665343137643863613632 +6432336361373838643733306565313830373065363663620a306163373632626366303837373530 +34393833656466326339383538363933313738616131373338336534393538366262306462616432 +6334343936346339320a333336623532383230643738333938366336636565343762376138333066 +36333964373865666534373830376132343636336139613835663830383432386237623935303239 +64613636316565326334643962326133313364323966303837303739653634373638326335623563 +38653763376234376533643561356561666438323238396162313662383566646362313732346538 +36376166313132393839383763393835626435333537313531323134373639303462373564613234 +34356664316562623336383535383431363366653238373130363362376361383361643762623533 +35323136333731343734393236613331616531343962366132653730613561346564316132396237 +64393163373561383961303137313666336338376161356464313563373031393463623266396138 +39653561663838393239633462626231313932386339623035396463623236633861333562666163 +65333035613038366639653565623362343163313561636666356364333263366162383639313363 +35636436376665626265643535663234623462626462633361373639613730616665346535626631 +31666333386433373734333830336662663331373666313231636437316136613137306233663433 +30633839343633366262653365383364366535613761303264353634366138326166316536643830 +34646336393939383630376537646538356439346235303036376239646662643933636130363266 +39363363393461333736343533643032353462396331336565663262363730336338333236613234 +65666535613363616263393933383233646566363962633163366136313636663963346163316430 +37313764633636303565366564643763656162396262663834653637613166353438666530303337 +34336533393738633862653262313930633336363038313634396666313331356566393436366263 +38363064656231393964323736666638316633346339366165633931646564383132353735343461 +64393231653039666536643638333431383333613364303438373564663635303763343062313630 +39303137656230626531 diff --git a/roles/bastion/tasks/main.yml b/roles/bastion/tasks/main.yml new file mode 100644 index 0000000..5b9f42b --- /dev/null +++ b/roles/bastion/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: Install Terraform + import_tasks: terraform.yml + +- name: Add SSH config/keys + import_tasks: ssh.yml diff --git a/roles/bastion/tasks/ssh.yml b/roles/bastion/tasks/ssh.yml new file mode 100644 index 0000000..dde7579 --- /dev/null +++ b/roles/bastion/tasks/ssh.yml @@ -0,0 +1,9 @@ +--- + +- name: Copy SSH config/keys + copy: + src: "ssh/" + dest: "~/.ssh/" + mode: 0600 + directory_mode: true + become_user: "{{ main_user }}" diff --git a/roles/bastion/tasks/terraform.yml b/roles/bastion/tasks/terraform.yml new file mode 100644 index 0000000..fafb22b --- /dev/null +++ b/roles/bastion/tasks/terraform.yml @@ -0,0 +1,16 @@ +--- + +- name: Create .tfvars_token_dtsv + template: + src: "tfvars_token.j2" + dest: "~/.tfvars_token_dtsv" + mode: 0640 + become_user: "{{ main_user }}" + +- name: Add .tfvars_token to .bash_profile + lineinfile: + path: "~/.bash_profile" + create: true + line: "source ~/.tfvars_token_dtsv" + mode: 0644 + become_user: "{{ main_user }}" diff --git a/roles/bastion/templates/tfvars_token.j2 b/roles/bastion/templates/tfvars_token.j2 new file mode 100644 index 0000000..34daadc --- /dev/null +++ b/roles/bastion/templates/tfvars_token.j2 @@ -0,0 +1,5 @@ +## Managed by Ansible ## + +export TF_VAR_dtsv_ionos_token='{{ vault_ionos_token_terraform }}' +export TF_VAR_dtsv_hcloud_token={{ vault_hcloud_token_terraform }} +export TF_VAR_dtsv_hcloud_ssh_key='{{ vault_hcloud_ssh_key }}' diff --git a/roles/bastion/vars/main.yml b/roles/bastion/vars/main.yml new file mode 100644 index 0000000..f24b091 --- /dev/null +++ b/roles/bastion/vars/main.yml @@ -0,0 +1,4 @@ +--- + +# Hetzner Cloud public ssh key +vault_hcloud_ssh_key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFpczZfQ5MrfjSYz8MnDHG4sM2cQ8cIsj3ALDGtmW3zu diff --git a/roles/common/files/public_keys.pub b/roles/common/files/public_keys.pub new file mode 100644 index 0000000..17123f7 --- /dev/null +++ b/roles/common/files/public_keys.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFpczZfQ5MrfjSYz8MnDHG4sM2cQ8cIsj3ALDGtmW3zu terraform diff --git a/roles/common/tasks/authorized_keys.yml b/roles/common/tasks/authorized_keys.yml new file mode 100644 index 0000000..341db85 --- /dev/null +++ b/roles/common/tasks/authorized_keys.yml @@ -0,0 +1,8 @@ +--- + +- name: Set authorized keys + authorized_key: + user: "{{ main_user }}" + key: "{{ lookup('file', 'public_keys.pub') }}" + state: present + exclusive: true # removing all the authorized keys already set diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..fd137d5 --- /dev/null +++ b/roles/common/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: Install system packages + import_tasks: system_packages.yml + +- name: Configure unattended upgrades + import_tasks: unattended_upgrades.yml + +- name: Add authorized_keys + import_tasks: authorized_keys.yml diff --git a/roles/common/tasks/system_packages.yml b/roles/common/tasks/system_packages.yml new file mode 100644 index 0000000..b8803d6 --- /dev/null +++ b/roles/common/tasks/system_packages.yml @@ -0,0 +1,7 @@ +--- +- name: Install common required system packages + apt: + name: "{{ common_system_packages }}" + state: latest + update_cache: true + cache_valid_time: 3600 diff --git a/roles/common/tasks/unattended_upgrades.yml b/roles/common/tasks/unattended_upgrades.yml new file mode 100644 index 0000000..75ae0d3 --- /dev/null +++ b/roles/common/tasks/unattended_upgrades.yml @@ -0,0 +1,15 @@ +--- + +- name: Modify auto-upgrades + replace: + path: /etc/apt/apt.conf.d/20auto-upgrades + regexp: "{{ item.regexp }}" + replace: "{{ item.replace }}" + loop: "{{ auto_upgrades }}" + +- name: Modify unattended-upgrades (enable recommended updates) + replace: + path: /etc/apt/apt.conf.d/50unattended-upgrades + regexp: "{{ item.regexp }}" + replace: "{{ item.replace }}" + loop: "{{ unattended_upgrades }}" diff --git a/roles/common/vars/main.yml b/roles/common/vars/main.yml new file mode 100644 index 0000000..7d5225f --- /dev/null +++ b/roles/common/vars/main.yml @@ -0,0 +1,15 @@ +--- +common_system_packages: + - "software-properties-common" + - "apt-transport-https" + - "ca-certificates" + +auto_upgrades: + - {regexp: 'APT::Periodic::Update-Package-Lists "0";', replace: 'APT::Periodic::Update-Package-Lists "1";'} + - {regexp: 'APT::Periodic::Unattended-Upgrade "0";', replace: 'APT::Periodic::Unattended-Upgrade "1";'} + +unattended_upgrades: + - {regexp: '\/\/.*\"\${distro_id}:\${distro_codename}-updates\";', replace: ' "${distro_id}:${distro_codename}-updates";'} + - {regexp: '\/\/.*Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";', replace: ' Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";'} + - {regexp: '\/\/.*Unattended-Upgrade::Remove-New-Unused-Dependencies "true";', replace: ' Unattended-Upgrade::Remove-New-Unused-Dependencies "true";'} + - {regexp: '\/\/.*Unattended-Upgrade::Remove-Unused-Dependencies "false";', replace: ' Unattended-Upgrade::Remove-Unused-Dependencies "true";'} diff --git a/roles/lego/handlers/main.yml b/roles/lego/handlers/main.yml new file mode 100644 index 0000000..97d7925 --- /dev/null +++ b/roles/lego/handlers/main.yml @@ -0,0 +1,14 @@ +--- +- name: restart lego_timer + systemd: + daemon_reload: true + enabled: true + name: lego.timer + state: restarted + +- name: restart lego_service + systemd: + daemon_reload: true + enabled: true + name: lego.service + state: restarted diff --git a/roles/lego/tasks/main.yml b/roles/lego/tasks/main.yml new file mode 100644 index 0000000..d74aed1 --- /dev/null +++ b/roles/lego/tasks/main.yml @@ -0,0 +1,67 @@ +--- +- name: Get latest lego version + github_release: + user: go-acme + repo: lego + action: latest_release + token: "{{ vault_github_token }}" + delegate_to: localhost + run_once: true + register: lego_version + +- name: Download lego {{ lego_version.tag }} from GitHub + get_url: + url: "https://github.com/go-acme/lego/releases/download/\ + {{ lego_version.tag }}/lego_{{ lego_version.tag }}\ + _linux_{{ deb_architecture }}.tar.gz" + dest: "/tmp/lego_{{ lego_version.tag }}_linux_{{ deb_architecture }}.tar.gz" + register: _download_archive + until: _download_archive is succeeded + retries: 3 + delay: 5 + +- name: unpack lego binaries + unarchive: + src: "/tmp/lego_{{ lego_version.tag }}_linux_{{ deb_architecture }}.tar.gz" + dest: "/tmp" + creates: "/tmp/lego_{{ lego_version.tag }}_linux_{{ deb_architecture }}" + remote_src: true + extra_opts: + - --one-top-level + +- name: Copy lego + copy: + src: "/tmp/lego_{{ lego_version.tag }}_linux_{{ deb_architecture }}/lego" + dest: "{{ lego_install_dir }}/lego" + remote_src: true + mode: 0755 + +- name: Create lego config directory + file: + path: "{{ lego_config_dir }}" + mode: 0755 + state: directory + +- name: Check lego registration + stat: + path: "{{ lego_config_dir }}/accounts" + register: account_dir + +- name: Register lego and create cert + command: | + {{ lego_install_dir }}/lego --accept-tos + {% for dns in certificate_domains %} + --domains="{{ dns }}" + {% endfor %} + {{ lego_cli_params|join(' ') }} + run + environment: '{ "{{ lego_provider|upper }}_API_KEY": "{{ vault_ionos_token_dns }}" }' + when: not account_dir.stat.exists + +- name: Copy lego systemd service + template: + src: "{{ item }}.j2" + dest: "/etc/systemd/system/{{ item }}" + mode: 0644 + loop: [lego.service, lego.timer] + notify: [restart lego_service, restart lego_timer] diff --git a/roles/lego/templates/lego.service.j2 b/roles/lego/templates/lego.service.j2 new file mode 100644 index 0000000..65526a5 --- /dev/null +++ b/roles/lego/templates/lego.service.j2 @@ -0,0 +1,19 @@ +## Managed by Ansible ## + +[Unit] +Description=Run lego renew +After=network-online.target + +[Service] +Type=oneshot +Environment={{ lego_provider|upper }}_API_KEY={{ vault_ionos_token_dns }} +ExecStart={{ lego_install_dir }}/lego \ + {% for dns in certificate_domains %} + --domains="{{ dns }}" \ + {% endfor %} + {{ lego_cli_params|join(' ') }} \ + renew +User=root + +[Install] +WantedBy=multi-user.target diff --git a/roles/lego/templates/lego.timer.j2 b/roles/lego/templates/lego.timer.j2 new file mode 100644 index 0000000..50b5a06 --- /dev/null +++ b/roles/lego/templates/lego.timer.j2 @@ -0,0 +1,12 @@ +## Managed by Ansible ## + +[Unit] +Description=Start lego renew + +[Timer] +Persistent=true +OnCalendar=Mon 05:00:00 +RandomizedDelaySec=3600 + +[Install] +WantedBy=timers.target \ No newline at end of file diff --git a/roles/lego/vars/main.yml b/roles/lego/vars/main.yml new file mode 100644 index 0000000..ce22567 --- /dev/null +++ b/roles/lego/vars/main.yml @@ -0,0 +1,21 @@ +--- +lego_install_dir: "/usr/local/bin" +lego_config_dir: "/etc/lego" +lego_provider: "ionos" +lego_cert_mail: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 32353064653631636431646333633664363866666439306235303138306461313266343939346463 + 6565636462656666366133653638333433393730656362360a333363623561646436613530623662 + 34623331313964316464653333646134353037333065373063346164623037663235316361646666 + 3466623937663061340a643863633034633665316364313065303166643363653366363063303261 + 34316163616637633837333539626337356563616566346561333439646565373665 +lego_cli_params: + - --path={{ lego_config_dir }} + - --email={{ lego_cert_mail }} + - --dns={{ lego_provider }} + - --key-type=ec384 + +# Certificates +certificate_domains: + - "twirling.de" + - "*.twirling.de" diff --git a/roles/nextcloud/defaults/main.yml b/roles/nextcloud/defaults/main.yml new file mode 100644 index 0000000..76ac890 --- /dev/null +++ b/roles/nextcloud/defaults/main.yml @@ -0,0 +1,2 @@ +--- +nextcloud_updater: false # update Nextcloud via updater.phar diff --git a/roles/nextcloud/handlers/main.yml b/roles/nextcloud/handlers/main.yml new file mode 100644 index 0000000..e791b1a --- /dev/null +++ b/roles/nextcloud/handlers/main.yml @@ -0,0 +1,44 @@ +--- + +- name: restart rclone_mount_nextcloud + systemd: + daemon_reload: true + enabled: true + name: rclone_mount_nextcloud.service + state: restarted + +- name: restart nextcloudcron + systemd: + daemon_reload: true + enabled: true + name: "{{ item }}" + state: restarted + loop: [nextcloudcron.service, nextcloudcron.timer] + +- name: restart nextcloud_nightlycron + systemd: + daemon_reload: true + enabled: true + name: nextcloud_nightlycron.timer + state: restarted + +- name: restart nextcloud_notify_push + systemd: + daemon_reload: true + enabled: true + name: nextcloud_notify_push.service + state: restarted + +- name: restart nextcloud_exporter + systemd: + daemon_reload: true + enabled: true + name: nextcloud_exporter.service + state: restarted + +- name: restart nextcloud_backup_timer + systemd: + daemon_reload: true + enabled: true + name: nextcloud_backup.timer + state: restarted diff --git a/roles/nextcloud/meta/main.yml b/roles/nextcloud/meta/main.yml new file mode 100644 index 0000000..4f1b9c2 --- /dev/null +++ b/roles/nextcloud/meta/main.yml @@ -0,0 +1,8 @@ +--- +dependencies: + - role: rclone + - role: systemd_exporter + vars: + systemd_exporter_include: '^rclone.*\.service|^nextcloud.*(cron|push)\..+' + - role: webserver + - role: redis diff --git a/roles/nextcloud/tasks/configure.yml b/roles/nextcloud/tasks/configure.yml new file mode 100644 index 0000000..2c3dc5b --- /dev/null +++ b/roles/nextcloud/tasks/configure.yml @@ -0,0 +1,145 @@ +--- + +- name: Configure .user.ini + lineinfile: + path: "{{ nextcloud_dir }}/.user.ini" + line: '{{ item.type }} {{ item.option }} {{ item.value }}' + create: true + owner: "{{ webserver_user }}" + group: "{{ webserver_group }}" + loop: "{{ nextcloud_user_ini }}" + +- name: Install apps + become: true + become_user: "{{ webserver_user }}" + command: php occ app:install {{ item }} + args: + chdir: "{{ nextcloud_dir }}" + creates: "{{ nextcloud_dir }}/apps/{{ item }}" + with_items: "{{ nextcloud_apps }}" + +- name: Set configs via occ + become: true + become_user: "{{ webserver_user }}" + command: php occ config:app:set {{ item }} + args: + chdir: "{{ nextcloud_dir }}" + loop: + - "preview jpeg_quality --value=60" + - "previewgenerator squareSizes --value='256 1024'" + - "previewgenerator widthSizes --value=2048" + - "previewgenerator heightSizes --value=2048" + - "files_trashbin background_job_expire_trash --value=no" + - "files_versions background_job_expire_versions --value=no" + when: not nextcloud_dir_stat.stat.exists + +- name: Get latest nextcloud_exporter version + github_release: + user: xperimental + repo: nextcloud-exporter + action: latest_release + token: "{{ vault_github_token }}" + delegate_to: localhost + run_once: true + register: nextcloud_exporter_version +- name: "{{ nextcloud_exporter_version }}" + set_fact: + nextcloud_exporter_version: "{{ nextcloud_exporter_version | replace ('v', '', 1) | trim }}" + run_once: true + +- name: download nextcloud_exporter {{ nextcloud_exporter_version.tag }} from GitHub + get_url: + url: "https://github.com/xperimental/nextcloud-exporter/releases/download/\ + v{{ nextcloud_exporter_version.tag }}/nextcloud-exporter-{{ nextcloud_exporter_version.tag }}\ + -{{ deb_architecture }}.bz2" + dest: "/tmp/nextcloud-exporter-{{ nextcloud_exporter_version.tag }}-{{ deb_architecture }}.bz2" + register: _download_archive + until: _download_archive is succeeded + retries: 3 + delay: 5 + +- name: decompress nextcloud_exporter binaries + command: + cmd: "bzip2 -dk nextcloud-exporter-{{ nextcloud_exporter_version.tag }}-{{ deb_architecture }}.bz2" + chdir: /tmp + creates: /tmp/nextcloud-exporter-{{ nextcloud_exporter_version.tag }}-{{ deb_architecture }} + +- name: Copy nextcloud_exporter + copy: + src: "/tmp/nextcloud-exporter-{{ nextcloud_exporter_version.tag }}-{{ deb_architecture }}" + dest: "{{ nextcloud_exporter_install_dir }}/nextcloud_exporter" + remote_src: true + owner: "{{ nextcloud_exporter_system_user }}" + group: "{{ nextcloud_exporter_system_group }}" + mode: 0755 + notify: restart nextcloud_exporter + +- name: Get latest nextcloud_notify_push version + github_release: + user: nextcloud + repo: notify_push + action: latest_release + token: "{{ vault_github_token }}" + delegate_to: localhost + run_once: true + register: nextcloud_notify_push_version +- name: "{{ nextcloud_notify_push_version }}" + set_fact: + nextcloud_notify_push_version: "{{ nextcloud_notify_push_version | replace ('v', '', 1) | trim }}" + run_once: true + +- name: "set deb_architecture alias" + set_fact: + deb_architecture_alias: "x86_64" + when: deb_architecture == "amd64" + +- name: "set deb_architecture alias" + set_fact: + deb_architecture_alias: "{{ deb_architecture }}" + when: deb_architecture != "amd64" + +- name: download nextcloud_notify_push {{ nextcloud_notify_push_version.tag }} from GitHub + get_url: + url: "https://github.com/nextcloud/notify_push/releases/download/v{{ nextcloud_notify_push_version.tag }}\ + /notify_push-{{ deb_architecture_alias }}-unknown-linux-musl" + dest: "/tmp/notify_push-{{ deb_architecture_alias }}-unknown-linux-musl" + register: _download_archive + until: _download_archive is succeeded + retries: 3 + delay: 5 + +- name: Copy nextcloud_notify_push + copy: + src: "/tmp/notify_push-{{ deb_architecture_alias }}-unknown-linux-musl" + dest: "{{ nextcloud_notify_push_install_dir }}/nextcloud_notify_push-{{ deb_architecture_alias }}" + remote_src: true + owner: "{{ webserver_user }}" + group: "{{ webserver_group }}" + mode: 0700 + notify: restart nextcloud_notify_push + +- name: Copy nextcloud_nightlycron + template: + src: nextcloud_nightlycron.sh.j2 + dest: "{{ nextcloud_background_script_dir }}/nextcloud_nightlycron.sh" + owner: "{{ webserver_user }}" + group: "{{ webserver_group }}" + mode: 0700 + +- name: Copy the Nextcloud systemd service file + template: + src: "{{ item }}.j2" + dest: "/etc/systemd/system/{{ item }}" + owner: root + group: root + mode: 0644 + loop: + - nextcloudcron.service + - nextcloudcron.timer + - nextcloud_notify_push.service + - nextcloud_exporter.service + - nextcloud_nightlycron.service + - nextcloud_nightlycron.timer + notify: + - restart {{ item | regex_replace ('\..*', '') }} + - restart systemd_exporter diff --git a/roles/nextcloud/tasks/dependencies.yml b/roles/nextcloud/tasks/dependencies.yml new file mode 100644 index 0000000..605fbe6 --- /dev/null +++ b/roles/nextcloud/tasks/dependencies.yml @@ -0,0 +1,25 @@ +--- +- name: Install required system packages + apt: + name: + - python3-pip + state: latest + update_cache: true + cache_valid_time: 3600 + +- name: Install required python packages + pip: + name: gtar # needed for latest nextcloud tar.bz archive + state: latest + +- name: Enable APCu + lineinfile: + path: /etc/php/{{ php_version }}/cli/conf.d/20-apcu.ini + line: apc.enable_cli=1 + notify: restart php-fpm + +- name: "Add {{ webserver_user }} user to redis group" + user: + name: "{{ webserver_user }}" + groups: redis + append: true diff --git a/roles/nextcloud/tasks/main.yml b/roles/nextcloud/tasks/main.yml new file mode 100644 index 0000000..54dcc88 --- /dev/null +++ b/roles/nextcloud/tasks/main.yml @@ -0,0 +1,13 @@ +--- + +- name: Configure rclone + import_tasks: rclone.yml + +- name: Configure dependencies + import_tasks: dependencies.yml + +- name: Check nextcloud + import_tasks: nextcloud.yml + +- name: Configure nextcloud + import_tasks: configure.yml diff --git a/roles/nextcloud/tasks/nextcloud.yml b/roles/nextcloud/tasks/nextcloud.yml new file mode 100644 index 0000000..e265d8c --- /dev/null +++ b/roles/nextcloud/tasks/nextcloud.yml @@ -0,0 +1,104 @@ +--- +# flush handlers to restart code-server before install extensions +- name: Flush handlers befor continue + meta: flush_handlers + +- name: Check nextcloud directory + stat: + path: '{{ nextcloud_dir }}' + register: nextcloud_dir_stat + +- name: Install Nextcloud + block: + - name: Create nextcloud directory + file: + path: "{{ nextcloud_dir }}" + state: directory + owner: "{{ webserver_user }}" + group: "{{ webserver_group }}" + mode: 0775 + force: false + + - name: unpack nextcloud latest from nextcloud.com + unarchive: + remote_src: true + src: "https://download.nextcloud.com/server/releases/latest.tar.bz2" + dest: "{{ nextcloud_dir }}" + owner: "{{ webserver_user }}" + group: "{{ webserver_group }}" + extra_opts: + - --strip-components=1 + + - name: Change directory ownership to webserver user + file: + path: "{{ item }}" + state: directory + recurse: true + owner: "{{ webserver_user }}" + group: "{{ webserver_group }}" + loop: + - "{{ nextcloud_dir }}" + - "{{ nextcloud_cache_dir }}" + - "{{ nextcloud_log_dir }}" + + - name: Copy default config + template: + src: "nextcloud.config.json.j2" + dest: /tmp/nextcloud.config.json + owner: "{{ webserver_user }}" + mode: 0600 + + - name: Ensure nextcloud installation is finished + become: true + become_user: "{{ webserver_user }}" + command: > + php occ maintenance:install + --database "pgsql" + --database-host "{{ nextcloud_db_host }}:{{ nextcloud_db_port }}" + --database-name "{{ nextcloud_db_name }}" + --database-user "{{ nextcloud_db_user }}" + --database-pass "{{ vault_nextcloud_db_pass }}" + --admin-user "{{ nexcloud_admin_user }}" + --admin-pass "{{ vault_nexcloud_admin_pass }}" + --data-dir "{{ nextcloud_data_dir }}" + args: + chdir: "{{ nextcloud_dir }}" + changed_when: true + + - name: Set default config + become: true + become_user: "{{ webserver_user }}" + command: php occ config:import /tmp/nextcloud.config.json + args: + chdir: "{{ nextcloud_dir }}" + + when: not nextcloud_dir_stat.stat.exists + +- name: Update Nextcloud + block: + - name: Run nextcloud's updater.phar in non-interactive way + become: true + become_user: "{{ webserver_user }}" + command: 'php updater/updater.phar --no-interaction' + args: + chdir: "{{ nextcloud_dir }}" + register: nextcloud_update_result + changed_when: "'Start update' in nextcloud_update_result.stdout" + + - name: Update result + debug: + msg: "{{ nextcloud_update_result.stdout_lines }}" + when: nextcloud_update_result.changed + + - name: DB tuning after update + become: true + become_user: "{{ webserver_user }}" + command: php occ {{ item }} + args: + chdir: "{{ nextcloud_dir }}" + loop: + - db:add-missing-indices + - db:convert-filecache-bigint + - integrity:check-core + when: nextcloud_update_result.changed + when: nextcloud_updater diff --git a/roles/nextcloud/tasks/rclone.yml b/roles/nextcloud/tasks/rclone.yml new file mode 100644 index 0000000..8322c67 --- /dev/null +++ b/roles/nextcloud/tasks/rclone.yml @@ -0,0 +1,30 @@ +--- +# ensure rclone.conf is present (meta role dependencies) + +- name: Create rclone mount dir + file: + path: "{{ nextcloud_rclone_mount_dir }}" + mode: 0755 + state: directory + +# Touch rclone log file to set permissions +- name: Touch rclone mount log file + file: + path: "{{ rclone_log_dir }}/mount_nextcloud.log" + state: touch + mode: 0644 + access_time: preserve + modification_time: preserve + +- name: Copy rclone mount nextcloud systemd service + template: + src: rclone_mount_nextcloud.service.j2 + dest: /etc/systemd/system/rclone_mount_nextcloud.service + mode: 0644 + notify: restart rclone_mount_nextcloud + +- name: "Add {{ webserver_user }} user to rclone group" + user: + name: "{{ webserver_user }}" + groups: rclone + append: true diff --git a/roles/nextcloud/templates/nextcloud.config.json.j2 b/roles/nextcloud/templates/nextcloud.config.json.j2 new file mode 100644 index 0000000..f8cbcb8 --- /dev/null +++ b/roles/nextcloud/templates/nextcloud.config.json.j2 @@ -0,0 +1,54 @@ +{ + "system": { + "trusted_proxies": {{ trusted_proxies | to_json }}, + "trusted_domains": [ + "{{ nextcloud_domain_name }}" + ], + "overwrite.cli.url": "https:\/\/{{ nextcloud_domain_name }}", + "datadirectory": "{{ nextcloud_data_dir }}", + "dbtype": "pgsql", + "dbname": "{{ nextcloud_db_name }}", + "dbhost": "{{ nextcloud_db_host }}", + "dbport": "{{ nextcloud_db_port }}", + "dbtableprefix": "oc_", + "dbuser": "{{ nextcloud_db_user }}", + "dbpassword": "{{ vault_nextcloud_db_pass }}", + "skeletondirectory": "", + "default_language": "de", + "default_phone_region": "DE", + "mail_smtpmode": "smtp", + "mail_smtphost": "{{ nextcloud_smtp_host }}", + "mail_smtpport": "{{ nextcloud_smtp_port }}", + "mail_smtptimeout": 10, + "mail_smtpauthtype": "LOGIN", + "mail_from_address": "{{ nextcloud_smtp_from_address }}", + "mail_sendmailmode": "smtp", + "mail_domain": "{{ nextcloud_smtp_from_domain }}", + "mail_smtpauth": 1, + "mail_smtpname": "{{ nextcloud_smtp_user }}", + "mail_smtppassword": "{{ nextcloud_smtp_pass }}", + "mail_smtpsecure": "ssl", + "loglevel": 1, + "logfile": {{ nextcloud_log_file | to_json }}, + "logtimezone": "Europe\/Berlin", + "memcache.local": "\\OC\\Memcache\\APCu", + "filelocking.enabled": true, + "memcache.distributed": "\\OC\\Memcache\\Redis", + "memcache.locking": "\\OC\\Memcache\\Redis", + "redis": { + "host": {{ redis_unixsocket | to_json }}, + "port": 0, + "timeout": 0, + "dbindex": 0 + }, + "trashbin_retention_obligation": "auto, 90", + "versions_retention_obligation": "auto, 180", + "tempdirectory": {{ nextcloud_temp_dir | to_json }}, + "cache_path": {{ nextcloud_cache_dir | to_json }}, + "localstorage.allowsymlinks": true, + "enable_previews": "true", + "preview_max_x": "2048", + "preview_max_y": "2048", + "preview_max_scale_factor": 1 + } +} diff --git a/roles/nextcloud/templates/nextcloud_exporter.service.j2 b/roles/nextcloud/templates/nextcloud_exporter.service.j2 new file mode 100644 index 0000000..8a25c80 --- /dev/null +++ b/roles/nextcloud/templates/nextcloud_exporter.service.j2 @@ -0,0 +1,15 @@ +## Managed by Ansible ## + +[Unit] +Description=Nextcloud Exporter +After=network-online.target + +[Service] +User={{ nextcloud_exporter_system_user }} +Group={{ nextcloud_exporter_system_group }} +Type=simple +ExecStart={{ nextcloud_exporter_install_dir }}/nextcloud_exporter --server https://{{ nextcloud_domain_name }} --auth-token {{ vault_nextcloud_exporter_token }} +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/roles/nextcloud/templates/nextcloud_nightlycron.service.j2 b/roles/nextcloud/templates/nextcloud_nightlycron.service.j2 new file mode 100644 index 0000000..ab6608f --- /dev/null +++ b/roles/nextcloud/templates/nextcloud_nightlycron.service.j2 @@ -0,0 +1,12 @@ +## Managed by Ansible ## + +[Unit] +Description = Nextcloud nightly background job + +[Service] +Type=simple +User={{ webserver_user }} +ExecStart=/usr/local/bin/nextcloud_nightlycron.sh + +[Install] +WantedBy=multi-user.target diff --git a/roles/nextcloud/templates/nextcloud_nightlycron.sh.j2 b/roles/nextcloud/templates/nextcloud_nightlycron.sh.j2 new file mode 100644 index 0000000..f289ffe --- /dev/null +++ b/roles/nextcloud/templates/nextcloud_nightlycron.sh.j2 @@ -0,0 +1,10 @@ +#!/bin/bash + +## Managed by Ansible ## + +cd {{ nextcloud_dir }} +# Print start status message. +echo "delete expired versions" +/usr/bin/php occ versions:expire --quiet +echo "permanently delete trashed files" +/usr/bin/php occ trashbin:expire --quiet diff --git a/roles/nextcloud/templates/nextcloud_nightlycron.timer.j2 b/roles/nextcloud/templates/nextcloud_nightlycron.timer.j2 new file mode 100644 index 0000000..a71b0e5 --- /dev/null +++ b/roles/nextcloud/templates/nextcloud_nightlycron.timer.j2 @@ -0,0 +1,12 @@ +## Managed by Ansible ## + +[Unit] +Description=Run Nextcloud nightly background job every night + +[Timer] +OnCalendar=02:00:00 +RandomizedDelaySec=600 +Unit=nextcloud_nightlycron.service + +[Install] +WantedBy=timers.target diff --git a/roles/nextcloud/templates/nextcloud_notify_push.service.j2 b/roles/nextcloud/templates/nextcloud_notify_push.service.j2 new file mode 100644 index 0000000..bab1a18 --- /dev/null +++ b/roles/nextcloud/templates/nextcloud_notify_push.service.j2 @@ -0,0 +1,17 @@ +## Managed by Ansible ## + +[Unit] +Description = Push daemon for Nextcloud clients + +[Service] +Environment = SOCKET_PATH={{ nextcloud_notify_push_socket }} METRICS_PORT=9206 +User={{ webserver_user }} +Group={{ webserver_user }} +RuntimeDirectory=nextcloud +RuntimeDirectoryMode=0750 +PIDFile=/run/nextcloud/notify_push.pid +ExecStart = {{ nextcloud_notify_push_install_dir }}/nextcloud_notify_push-{{ deb_architecture_alias }} {{ nextcloud_dir }}/config/config.php +Restart=always + +[Install] +WantedBy = multi-user.target diff --git a/roles/nextcloud/templates/nextcloudcron.service.j2 b/roles/nextcloud/templates/nextcloudcron.service.j2 new file mode 100644 index 0000000..a102765 --- /dev/null +++ b/roles/nextcloud/templates/nextcloudcron.service.j2 @@ -0,0 +1,9 @@ +## Managed by Ansible ## + +[Unit] +Description=Nextcloud background job (cron.php) + +[Service] +User={{ webserver_user }} +ExecStart=/usr/bin/php -f /var/www/nextcloud/cron.php +KillMode=process diff --git a/roles/nextcloud/templates/nextcloudcron.timer.j2 b/roles/nextcloud/templates/nextcloudcron.timer.j2 new file mode 100644 index 0000000..8d2c9a2 --- /dev/null +++ b/roles/nextcloud/templates/nextcloudcron.timer.j2 @@ -0,0 +1,12 @@ +## Managed by Ansible ## + +[Unit] +Description=Run Nextcloud background job (cron.php) every 5min + +[Timer] +OnBootSec=5min +OnUnitActiveSec=5min +Unit=nextcloudcron.service + +[Install] +WantedBy=timers.target diff --git a/roles/nextcloud/templates/rclone_mount_nextcloud.service.j2 b/roles/nextcloud/templates/rclone_mount_nextcloud.service.j2 new file mode 100644 index 0000000..c54e0b0 --- /dev/null +++ b/roles/nextcloud/templates/rclone_mount_nextcloud.service.j2 @@ -0,0 +1,47 @@ +## Managed by Ansible ## + +[Unit] +Description = rclone crypt mount {{ nextcloud_rclone_mount_dir }} +After = network-online.target + +[Service] +Environment=RCLONE_RCD_USER=rclone +Environment=RCLONE_RCD_PASSWORD={{ vault_rclone_rcd_pass }} +Type=notify +ExecStart=/usr/bin/rclone mount GD3_crypt:cloud_data {{ nextcloud_rclone_mount_dir }} \ + --devname rclone \ + --use-mmap \ + --allow-other \ + --uid {{ created_rclone_user.uid }} \ + --gid {{ created_rclone_group.gid }} \ + --umask 002 \ + --dir-perms 775 \ + --file-perms 664 \ + --dir-cache-time 8760h \ + --poll-interval 1h \ + --buffer-size 32M \ + --drive-chunk-size 256M \ + --drive-pacer-min-sleep 10ms \ + --drive-pacer-burst 1000 \ + --vfs-cache-max-age 720h \ + --vfs-cache-mode full \ + --vfs-cache-max-size 100G \ + --vfs-read-chunk-size 128M \ + --vfs-read-chunk-size-limit off \ + --vfs-write-back 20s \ + --cache-dir={{ rclone_cache_dir }} \ + --log-file={{ rclone_log_dir }}/mount_nextcloud.log \ + --log-level=INFO \ + --rc \ + --rc-addr "0.0.0.0:5572" \ + --rc-enable-metrics \ + --rc-user $RCLONE_RCD_USER \ + --rc-pass $RCLONE_RCD_PASSWORD \ + --user-agent "{{ rclone_user_agent_gd }}" +ExecStop=/bin/fusermount -u -z {{ nextcloud_rclone_mount_dir }} +Restart=on-failure +RestartSec=20s +User=root + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/nextcloud/vars/main.yml b/roles/nextcloud/vars/main.yml new file mode 100644 index 0000000..91cc752 --- /dev/null +++ b/roles/nextcloud/vars/main.yml @@ -0,0 +1,87 @@ +--- +# Rclone +nextcloud_rclone_mount_dir: "/mnt/cloud_data" +nextcloud_scripts_path: "/root/.scripts" + +# Nextcloud +nextcloud_dir: "/var/www/nextcloud" +nextcloud_data_dir: "{{ hcloud_webserver_volume_path }}/nextcloud_data" +nextcloud_temp_dir: "/tmp" +nextcloud_cache_dir: "/var/cache/nextcloud" +nextcloud_log_dir: "/var/log/nextcloud" +nextcloud_log_file: "{{ nextcloud_log_dir }}/nextcloud.log" +nextcloud_domain_name: "cloud.{{ webserver_domain }}" +nexcloud_admin_user: "admin-{{ lookup('community.general.random_string', length=6, upper=false, special=false) }}" +vault_nexcloud_admin_pass: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 64373333336533333764643235613338306437306134333831393434326631306165653336383732 + 3537313164663762373636316462346438663634393237340a613565633865663665396531616133 + 39373637653839623736653531636361633739643137386537633464653332373066366336336532 + 6566313533383031310a663863616164633331313431396362373161646531663134313637626263 + 6562 +trusted_proxies: + - "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" + - "{{ hostvars[inventory_hostname]['ansible_default_ipv6']['address'] }}" +nextcloud_trashbin_retention_obligation: "auto, 90" +nextcloud_versions_retention_obligation: "auto, 30" +nextcloud_max_upload_size: "50G" +# database +nextcloud_db_host: "{{ pgsql_server_ip }}" +nextcloud_db_port: "{{ pgsql_server_port }}" +nextcloud_db_name: "nextcloud_db" +nextcloud_db_user: "nextcloud_db_user" +vault_nextcloud_db_pass: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 61393238366632366635373432343739373830393635656139643532663737313661643062626566 + 6538383561323332313231313235666437636631363030630a386665373562613936303038626638 + 63303861306461353734316530653231343132376130373835643236653836303031626431326265 + 3461333932626438630a393134653333323431323631653235643639316634383938666264623339 + 66323964336436303934373833353161313163353734343637303165393431376262323065306362 + 6664303132626565316665306263373761626139316432666333 +# mailer +nextcloud_smtp_host: "{{ smtp_hostname }}" +nextcloud_smtp_port: "{{ smtp_port }}" +nextcloud_smtp_from_address: "cloud" +nextcloud_smtp_from_domain: "twirling.de" +nextcloud_smtp_user: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 37323762356630343133346634653965303530363966646236383962313163623637326165346439 + 3234303935353134633238396365363036313363663031310a663339363665376564306565393538 + 33663566663534383133623965316362383731303565326632623430303565343134393939343734 + 3930376165653536310a656632373336623663356431333136303165653162333137626632333033 + 35363439346237666662333537613363386266653865656238323638666533356535 +nextcloud_smtp_pass: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 61303737376466646164313766373639376133633935313433356637323038626437663736363631 + 3864616433353737666137663663666333366463626337630a643034323935613833633439306236 + 36373763393762376533393663303436373939356561363036366535666134613731316530626536 + 6231626666643937340a326134636337666130356639383864346639316535663638636266323535 + 6562 + +nextcloud_user_ini: + - {type: php_value, option: upload_max_filesize, value: 50GB} + - {type: php_value, option: post_max_size, value: 50GB} + - {type: php_value, option: max_input_time, value: 3600} + - {type: php_value, option: max_execution_time, value: 3600} + +nextcloud_apps: + - breezedark + - calendar + - contacts + - external + - extract + - files_external + - groupfolders + - notes + - notify_push + - tasks + - twofactor_totp + +nextcloud_exporter_install_dir: "/usr/local/bin" +nextcloud_exporter_system_group: "node-exporter" +nextcloud_exporter_system_user: "{{ nextcloud_exporter_system_group }}" +vault_nextcloud_exporter_token: secret + +nextcloud_notify_push_install_dir: "/usr/local/bin" +nextcloud_notify_push_socket: "/run/nextcloud/notify_push.sock" +nextcloud_background_script_dir: "/usr/local/bin" diff --git a/roles/nginx/handlers/main.yml b/roles/nginx/handlers/main.yml new file mode 100644 index 0000000..715758d --- /dev/null +++ b/roles/nginx/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: reload nginx + systemd: + name: nginx.service + state: reloaded diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml new file mode 100644 index 0000000..2fb9ae4 --- /dev/null +++ b/roles/nginx/tasks/main.yml @@ -0,0 +1,44 @@ +--- +- name: Add Nginx GPG apt Key + apt_key: + url: https://nginx.org/keys/nginx_signing.key + keyring: /usr/share/keyrings/nginx-archive-keyring.gpg + state: present + +- name: Add Nginx Mainline Repository + apt_repository: + repo: "deb [arch={{ deb_architecture }} signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ + http://nginx.org/packages/mainline/ubuntu {{ ansible_distribution_release }} nginx" + state: present + update_cache: true + +- name: Install Nginx + apt: + name: nginx + state: latest + update_cache: true + cache_valid_time: 3600 + +- name: Remove default.conf + ansible.builtin.file: + path: /etc/nginx/conf.d/default.conf + state: absent + +- name: Create global config folder + file: + path: "/etc/nginx/global" + mode: 0755 + state: directory + +- name: Copy Nginx SSL Config + template: + dest: /etc/nginx/global/ssl.conf + src: ssl.conf.j2 + mode: 0644 + notify: reload nginx + +- name: Download pre-defined DHE group # as recommended by IETF RFC 7919 + get_url: + url: https://github.com/internetstandards/dhe_groups/raw/main/ffdhe4096.pem + dest: "{{ nginx_ssl_dhparam }}" + notify: reload nginx diff --git a/roles/nginx/templates/ssl.conf.j2 b/roles/nginx/templates/ssl.conf.j2 new file mode 100644 index 0000000..38c887a --- /dev/null +++ b/roles/nginx/templates/ssl.conf.j2 @@ -0,0 +1,17 @@ +## Managed by Ansible ## + +# Configure SSL + ssl_ciphers "{{ nginx_ssl_ciphers }}"; + ssl_protocols {{ nginx_ssl_protocols }}; + ssl_prefer_server_ciphers off; + ssl_early_data on; + ssl_dhparam {{ nginx_ssl_dhparam }}; +# OCSP Stapling fetch OCSP records from URL in ssl_certificate and cache them + ssl_stapling on; + ssl_stapling_verify on; + resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001]; +# SSL session handling + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 1d; + ssl_session_tickets off; + ssl_buffer_size 4k; \ No newline at end of file diff --git a/roles/nginx/vars/main.yml b/roles/nginx/vars/main.yml new file mode 100644 index 0000000..d61236c --- /dev/null +++ b/roles/nginx/vars/main.yml @@ -0,0 +1,7 @@ +--- + +nginx_ssl_ciphers: "ALL:!AES128:!CAMELLIA128:!CAMELLIA:!ARIA128:!RSA:!SEED:!aNULL:!eNULL:!EXPORT:\ + !DES:!RC4:!3DES:!MD5:!PSK:!DHE-RSA-AES256:!ECDHE-RSA-AES256-SHA384:\ + !DHE-RSA-AES256-SHA256:!ECDHE-RSA-AES256-SHA:!DHE-RSA-AES256-SHA:@STRENGTH" +nginx_ssl_protocols: "TLSv1.2 TLSv1.3" +nginx_ssl_dhparam: "/etc/ssl/dhparams.pem" diff --git a/roles/node_exporter/handlers/main.yml b/roles/node_exporter/handlers/main.yml new file mode 100644 index 0000000..671c3e7 --- /dev/null +++ b/roles/node_exporter/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: restart node_exporter + systemd: + daemon_reload: true + enabled: true + name: node_exporter.service + state: restarted diff --git a/roles/node_exporter/tasks/main.yml b/roles/node_exporter/tasks/main.yml new file mode 100644 index 0000000..3ad1edd --- /dev/null +++ b/roles/node_exporter/tasks/main.yml @@ -0,0 +1,69 @@ +--- +- name: Create node_exporter group + group: + name: "{{ node_exporter_system_group }}" + state: present + system: true + when: node_exporter_system_group != "root" + +- name: Create node_exporter user + user: + name: "{{ node_exporter_system_user }}" + group: "{{ node_exporter_system_group }}" + groups: "{{ node_exporter_system_group }}" + append: true + shell: /usr/sbin/nologin + system: true + create_home: false + home: / + +- name: Get latest node_exporter version + github_release: + user: prometheus + repo: node_exporter + action: latest_release + token: "{{ vault_github_token }}" + delegate_to: localhost + run_once: true + register: node_exporter_version +- name: "{{ node_exporter_version }}" + set_fact: + node_exporter_version: "{{ node_exporter_version | replace ('v', '', 1) | trim }}" + run_once: true + +- name: download node_exporter {{ node_exporter_version.tag }} from GitHub + get_url: + url: "https://github.com/prometheus/node_exporter/releases/download/\ + v{{ node_exporter_version.tag }}/node_exporter-{{ node_exporter_version.tag }}\ + .linux-{{ deb_architecture }}.tar.gz" + dest: "/tmp/node_exporter-{{ node_exporter_version.tag }}-linux-{{ deb_architecture }}.tar.gz" + register: _download_archive + until: _download_archive is succeeded + retries: 3 + delay: 5 + +- name: unpack node_exporter binaries + unarchive: + src: "/tmp/node_exporter-{{ node_exporter_version.tag }}-linux-{{ deb_architecture }}.tar.gz" + dest: "/tmp" + creates: "node_exporter-{{ node_exporter_version.tag }}.linux-{{ deb_architecture }}" + remote_src: true + +- name: Copy node_exporter + copy: + src: "/tmp/node_exporter-{{ node_exporter_version.tag }}.linux-{{ deb_architecture }}/node_exporter" + dest: "{{ node_exporter_install_dir }}/node_exporter" + remote_src: true + owner: "{{ node_exporter_system_user }}" + group: "{{ node_exporter_system_group }}" + mode: 0755 + notify: restart node_exporter + +- name: Copy node_exporter systemd service + template: + src: node_exporter.service.j2 + dest: /etc/systemd/system/node_exporter.service + owner: root + group: root + mode: 0644 + notify: restart node_exporter diff --git a/roles/node_exporter/templates/node_exporter.service.j2 b/roles/node_exporter/templates/node_exporter.service.j2 new file mode 100644 index 0000000..672e935 --- /dev/null +++ b/roles/node_exporter/templates/node_exporter.service.j2 @@ -0,0 +1,16 @@ +## Managed by Ansible ## + +[Unit] +Description=Prometheus Node Exporter +After=network-online.target + +[Service] +Type=simple +User={{ node_exporter_system_user }} +Group={{ node_exporter_system_group }} +ExecStart={{ node_exporter_install_dir }}/node_exporter --collector.filesystem.ignored-mount-points=^/(sys|proc|dev|run)($|/) +Restart=always +RestartSec=1 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/node_exporter/vars/main.yml b/roles/node_exporter/vars/main.yml new file mode 100644 index 0000000..d778283 --- /dev/null +++ b/roles/node_exporter/vars/main.yml @@ -0,0 +1,5 @@ +--- +# Variables +node_exporter_install_dir: "/usr/local/bin" +node_exporter_system_group: "node-exporter" +node_exporter_system_user: "{{ node_exporter_system_group }}" diff --git a/roles/php/defaults/main.yml b/roles/php/defaults/main.yml new file mode 100644 index 0000000..e1a64c6 --- /dev/null +++ b/roles/php/defaults/main.yml @@ -0,0 +1,5 @@ +--- +# Default PHP installation without version/module specification +# php_old_version: # specify old verison to uninstall +php_version: "8.1" +php_modules: ["common"] diff --git a/roles/php/handlers/main.yml b/roles/php/handlers/main.yml new file mode 100644 index 0000000..afe0251 --- /dev/null +++ b/roles/php/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart php-fpm + systemd: + name: php{{ php_version }}-fpm.service + state: reloaded diff --git a/roles/php/meta/main.yml b/roles/php/meta/main.yml new file mode 100644 index 0000000..8b662c9 --- /dev/null +++ b/roles/php/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: nginx diff --git a/roles/php/tasks/main.yml b/roles/php/tasks/main.yml new file mode 100644 index 0000000..52b7651 --- /dev/null +++ b/roles/php/tasks/main.yml @@ -0,0 +1,29 @@ +--- +- name: Add Sury PHP Repository + apt_repository: + repo: ppa:ondrej/php + state: present + update_cache: true + when: php_version is defined # add repo when version is specified, otherwise use default repo + +- name: "Uninstall old PHP version" + apt: + name: "php{{ php_old_version }}*" + state: absent + purge: true + when: php_old_version is defined # uninstall when old version is specified + +- name: "Install custom PHP modules {{ php_modules }}" + apt: + name: "{{ ['php' + php_version] | product(php_modules) | map('join', '-') | list }}" + state: latest + update_cache: true + cache_valid_time: 3600 + +- name: Copy Nginx PHP-Handler + template: + dest: /etc/nginx/conf.d/php-handler.conf + src: php-handler.conf.j2 + mode: 0644 + when: '"fpm" in php_modules' + notify: reload nginx diff --git a/roles/php/templates/php-handler.conf.j2 b/roles/php/templates/php-handler.conf.j2 new file mode 100644 index 0000000..3dea17a --- /dev/null +++ b/roles/php/templates/php-handler.conf.j2 @@ -0,0 +1,6 @@ +## Managed by Ansible ## + +# PHP Handler +upstream php-handler { + server unix:{{ php_socket }}; +} diff --git a/roles/php/vars/main.yml b/roles/php/vars/main.yml new file mode 100644 index 0000000..243010f --- /dev/null +++ b/roles/php/vars/main.yml @@ -0,0 +1,2 @@ +--- +php_socket: "/run/php/php{{ php_version }}-fpm.sock" diff --git a/roles/postgresql/handlers/main.yml b/roles/postgresql/handlers/main.yml new file mode 100644 index 0000000..ab1582d --- /dev/null +++ b/roles/postgresql/handlers/main.yml @@ -0,0 +1,17 @@ +--- +- name: restart postgresql + systemd: + name: postgresql.service + state: restarted + +- name: reload postgresql + systemd: + name: postgresql.service + state: reloaded + +- name: restart postgres_exporter + systemd: + daemon_reload: true + enabled: true + name: postgres_exporter.service + state: restarted diff --git a/roles/postgresql/meta/main.yml b/roles/postgresql/meta/main.yml new file mode 100644 index 0000000..7eeb39e --- /dev/null +++ b/roles/postgresql/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + # - role: rclone # for backup diff --git a/roles/postgresql/tasks/main.yml b/roles/postgresql/tasks/main.yml new file mode 100644 index 0000000..ca0da6a --- /dev/null +++ b/roles/postgresql/tasks/main.yml @@ -0,0 +1,7 @@ +--- + +- name: Install postgresql + import_tasks: postgresql.yml + +- name: Install postgresql exporter + import_tasks: postgres_exporter.yml diff --git a/roles/postgresql/tasks/postgres_exporter.yml b/roles/postgresql/tasks/postgres_exporter.yml new file mode 100644 index 0000000..c9e97e4 --- /dev/null +++ b/roles/postgresql/tasks/postgres_exporter.yml @@ -0,0 +1,50 @@ +--- + +- name: Get latest postgres_exporter version + github_release: + user: prometheus-community + repo: postgres_exporter + action: latest_release + token: "{{ vault_github_token }}" + delegate_to: localhost + run_once: true + register: postgres_exporter_version +- name: "{{ postgres_exporter_version }}" + set_fact: + postgres_exporter_version: "{{ postgres_exporter_version | replace ('v', '', 1) | trim }}" + run_once: true + +- name: download postgres_exporter {{ postgres_exporter_version.tag }} from GitHub + get_url: + url: "https://github.com/prometheus-community/postgres_exporter/releases/download/\ + v{{ postgres_exporter_version.tag }}/postgres_exporter-{{ postgres_exporter_version.tag }}\ + .linux-{{ deb_architecture }}.tar.gz" + dest: "/tmp/postgres_exporter-{{ postgres_exporter_version.tag }}-linux-{{ deb_architecture }}.tar.gz" + register: _download_archive + until: _download_archive is succeeded + retries: 3 + delay: 5 + +- name: unpack postgres_exporter binaries + unarchive: + src: "/tmp/postgres_exporter-{{ postgres_exporter_version.tag }}-linux-{{ deb_architecture }}.tar.gz" + dest: "/tmp" + creates: "/tmp/postgres_exporter-{{ postgres_exporter_version.tag }}.linux-{{ deb_architecture }}" + remote_src: true + +- name: Copy postgres_exporter + copy: + src: "/tmp/postgres_exporter-{{ postgres_exporter_version.tag }}.linux-{{ deb_architecture }}/postgres_exporter" + dest: "{{ pgsql_exporter_install_dir }}/postgres_exporter" + remote_src: true + mode: 0755 + notify: restart postgres_exporter + +- name: Copy the postgres_exporter systemd service file + template: + src: postgres_exporter.service.j2 + dest: /etc/systemd/system/postgres_exporter.service + owner: root + group: root + mode: 0644 + notify: restart postgres_exporter diff --git a/roles/postgresql/tasks/postgresql.yml b/roles/postgresql/tasks/postgresql.yml new file mode 100644 index 0000000..c26789b --- /dev/null +++ b/roles/postgresql/tasks/postgresql.yml @@ -0,0 +1,34 @@ +--- +- name: Add PostgreSQL GPG apt key + apt_key: + url: https://www.postgresql.org/media/keys/ACCC4CF8.asc + keyring: /usr/share/keyrings/apt.postgresql.org.gpg + state: present + +- name: Add PostgreSQL Repository + apt_repository: + repo: "deb [arch={{ deb_architecture }} signed-by=/usr/share/keyrings/apt.postgresql.org.gpg] \ + http://apt.postgresql.org/pub/repos/apt {{ ansible_distribution_release }}-pgdg main" + state: present + update_cache: true + +- name: Install PostgreSQL + apt: + name: "postgresql-{{ pgsql_server_version }}" + state: latest + update_cache: true + cache_valid_time: 3600 + +- name: Create PostgreSQL Config + template: + dest: "/etc/postgresql/{{ pgsql_server_version }}/main/postgresql.conf" + src: "postgresql.conf.j2" + mode: 0644 + notify: restart postgresql + +- name: Create PostgreSQL Client Authentication Config + template: + dest: "/etc/postgresql/{{ pgsql_server_version }}/main/pg_hba.conf" + src: "pg_hba.conf.j2" + mode: 0644 + notify: reload postgresql diff --git a/roles/postgresql/templates/pg_hba.conf.j2 b/roles/postgresql/templates/pg_hba.conf.j2 new file mode 100644 index 0000000..986df40 --- /dev/null +++ b/roles/postgresql/templates/pg_hba.conf.j2 @@ -0,0 +1,111 @@ +## Managed by Ansible ## + +# PostgreSQL Client Authentication Configuration File +# =================================================== +# +# Refer to the "Client Authentication" section in the PostgreSQL +# documentation for a complete description of this file. A short +# synopsis follows. +# +# This file controls: which hosts are allowed to connect, how clients +# are authenticated, which PostgreSQL user names they can use, which +# databases they can access. Records take one of these forms: +# +# local DATABASE USER METHOD [OPTIONS] +# host DATABASE USER ADDRESS METHOD [OPTIONS] +# hostssl DATABASE USER ADDRESS METHOD [OPTIONS] +# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS] +# hostgssenc DATABASE USER ADDRESS METHOD [OPTIONS] +# hostnogssenc DATABASE USER ADDRESS METHOD [OPTIONS] +# +# (The uppercase items must be replaced by actual values.) +# +# The first field is the connection type: +# - "local" is a Unix-domain socket +# - "host" is a TCP/IP socket (encrypted or not) +# - "hostssl" is a TCP/IP socket that is SSL-encrypted +# - "hostnossl" is a TCP/IP socket that is not SSL-encrypted +# - "hostgssenc" is a TCP/IP socket that is GSSAPI-encrypted +# - "hostnogssenc" is a TCP/IP socket that is not GSSAPI-encrypted +# +# DATABASE can be "all", "sameuser", "samerole", "replication", a +# database name, or a comma-separated list thereof. The "all" +# keyword does not match "replication". Access to replication +# must be enabled in a separate record (see example below). +# +# USER can be "all", a user name, a group name prefixed with "+", or a +# comma-separated list thereof. In both the DATABASE and USER fields +# you can also write a file name prefixed with "@" to include names +# from a separate file. +# +# ADDRESS specifies the set of hosts the record matches. It can be a +# host name, or it is made up of an IP address and a CIDR mask that is +# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that +# specifies the number of significant bits in the mask. A host name +# that starts with a dot (.) matches a suffix of the actual host name. +# Alternatively, you can write an IP address and netmask in separate +# columns to specify the set of hosts. Instead of a CIDR-address, you +# can write "samehost" to match any of the server's own IP addresses, +# or "samenet" to match any address in any subnet that the server is +# directly connected to. +# +# METHOD can be "trust", "reject", "md5", "password", "scram-sha-256", +# "gss", "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert". +# Note that "password" sends passwords in clear text; "md5" or +# "scram-sha-256" are preferred since they send encrypted passwords. +# +# OPTIONS are a set of options for the authentication in the format +# NAME=VALUE. The available options depend on the different +# authentication methods -- refer to the "Client Authentication" +# section in the documentation for a list of which options are +# available for which authentication methods. +# +# Database and user names containing spaces, commas, quotes and other +# special characters must be quoted. Quoting one of the keywords +# "all", "sameuser", "samerole" or "replication" makes the name lose +# its special character, and just match a database or username with +# that name. +# +# This file is read on server startup and when the server receives a +# SIGHUP signal. If you edit the file on a running system, you have to +# SIGHUP the server for the changes to take effect, run "pg_ctl reload", +# or execute "SELECT pg_reload_conf()". +# +# Put your actual configuration here +# ---------------------------------- +# +# If you want to allow non-local connections, you need to add more +# "host" records. In that case you will also need to make PostgreSQL +# listen on a non-local interface via the listen_addresses +# configuration parameter, or via the -i or -h command line switches. + + + + +# DO NOT DISABLE! +# If you change this first entry you will need to make sure that the +# database superuser can access the database using some other method. +# Noninteractive access to all databases is required during automatic +# maintenance (custom daily cronjobs, replication, and similar tasks). +# +# Database administrative login by Unix domain socket +local all postgres peer + +# TYPE DATABASE USER ADDRESS METHOD + +# "local" is for Unix domain socket connections only +local all all peer +# IPv4 local connections: +host all all 127.0.0.1/32 scram-sha-256 +# IPv6 local connections: +host all all ::1/128 scram-sha-256 +# Allow replication connections from localhost, by a user with the +# replication privilege. +local replication all peer +host replication all 127.0.0.1/32 scram-sha-256 +host replication all ::1/128 scram-sha-256 + +# Rules managed by Ansible +{% for client in pgsql_client_auth %} +host {{ client.db }} {{ client.user }} {{ client.address }} {{ client.method }} +{% endfor %} diff --git a/roles/postgresql/templates/postgres_exporter.service.j2 b/roles/postgresql/templates/postgres_exporter.service.j2 new file mode 100644 index 0000000..a74576c --- /dev/null +++ b/roles/postgresql/templates/postgres_exporter.service.j2 @@ -0,0 +1,18 @@ +## Managed by Ansible ## + +[Unit] +Description=PostgreSQL Exporter +After=network-online.target + +[Service] +Environment=PG_EXPORTER_AUTO_DISCOVER_DATABASES=true +Environment=PG_EXPORTER_EXCLUDE_DATABASES=postgres,template1,template0 +Environment=DATA_SOURCE_NAME="user=postgres host=/var/run/postgresql/ sslmode=disable" +User={{ pgsql_exporter_user }} +Type=simple +ExecStart=postgres_exporter +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/postgresql/templates/postgresql.conf.j2 b/roles/postgresql/templates/postgresql.conf.j2 new file mode 100644 index 0000000..c1932f5 --- /dev/null +++ b/roles/postgresql/templates/postgresql.conf.j2 @@ -0,0 +1,800 @@ +## Managed by Ansible ## + +# ----------------------------- +# PostgreSQL configuration file +# ----------------------------- +# +# This file consists of lines of the form: +# +# name = value +# +# (The "=" is optional.) Whitespace may be used. Comments are introduced with +# "#" anywhere on a line. The complete list of parameter names and allowed +# values can be found in the PostgreSQL documentation. +# +# The commented-out settings shown in this file represent the default values. +# Re-commenting a setting is NOT sufficient to revert it to the default value; +# you need to reload the server. +# +# This file is read on server startup and when the server receives a SIGHUP +# signal. If you edit the file on a running system, you have to SIGHUP the +# server for the changes to take effect, run "pg_ctl reload", or execute +# "SELECT pg_reload_conf()". Some parameters, which are marked below, +# require a server shutdown and restart to take effect. +# +# Any parameter can also be given as a command-line option to the server, e.g., +# "postgres -c log_connections=on". Some parameters can be changed at run time +# with the "SET" SQL command. +# +# Memory units: B = bytes Time units: us = microseconds +# kB = kilobytes ms = milliseconds +# MB = megabytes s = seconds +# GB = gigabytes min = minutes +# TB = terabytes h = hours +# d = days + + +#------------------------------------------------------------------------------ +# FILE LOCATIONS +#------------------------------------------------------------------------------ + +# The default values of these variables are driven from the -D command-line +# option or PGDATA environment variable, represented here as ConfigDir. + +data_directory = '/var/lib/postgresql/14/main' # use data in another directory + # (change requires restart) +hba_file = '/etc/postgresql/14/main/pg_hba.conf' # host-based authentication file + # (change requires restart) +ident_file = '/etc/postgresql/14/main/pg_ident.conf' # ident configuration file + # (change requires restart) + +# If external_pid_file is not explicitly set, no extra PID file is written. +external_pid_file = '/var/run/postgresql/14-main.pid' # write an extra PID file + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONNECTIONS AND AUTHENTICATION +#------------------------------------------------------------------------------ + +# - Connection Settings - + +listen_addresses = '{{ pgsql_listen_addresses }}' + # what IP address(es) to listen on; + # comma-separated list of addresses; + # defaults to 'localhost'; use '*' for all + # (change requires restart) +port = {{ pgsql_server_port }} +max_connections = {{ pgsql_max_connections }} +#superuser_reserved_connections = 3 # (change requires restart) +unix_socket_directories = '{{ pgsql_unix_socket }}' +#unix_socket_group = '' # (change requires restart) +#unix_socket_permissions = 0777 # begin with 0 to use octal notation + # (change requires restart) +#bonjour = off # advertise server via Bonjour + # (change requires restart) +#bonjour_name = '' # defaults to the computer name + # (change requires restart) + +# - TCP settings - +# see "man tcp" for details + +#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; + # 0 selects the system default +#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; + # 0 selects the system default +#tcp_keepalives_count = 0 # TCP_KEEPCNT; + # 0 selects the system default +#tcp_user_timeout = 0 # TCP_USER_TIMEOUT, in milliseconds; + # 0 selects the system default + +#client_connection_check_interval = 0 # time between checks for client + # disconnection while running queries; + # 0 for never + +# - Authentication - + +#authentication_timeout = 1min # 1s-600s +password_encryption = {{ pgsql_password_encryption }} +#db_user_namespace = off + +# GSSAPI using Kerberos +#krb_server_keyfile = 'FILE:${sysconfdir}/krb5.keytab' +#krb_caseins_users = off + +# - SSL - + +ssl = on +#ssl_ca_file = '' +ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem' +#ssl_crl_file = '' +#ssl_crl_dir = '' +ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key' +#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers +#ssl_prefer_server_ciphers = on +#ssl_ecdh_curve = 'prime256v1' +#ssl_min_protocol_version = 'TLSv1.2' +#ssl_max_protocol_version = '' +#ssl_dh_params_file = '' +#ssl_passphrase_command = '' +#ssl_passphrase_command_supports_reload = off + + +#------------------------------------------------------------------------------ +# RESOURCE USAGE (except WAL) +#------------------------------------------------------------------------------ + +# - Memory - + +shared_buffers = {{ pgsql_shared_buffers }} + # (change requires restart) +#huge_pages = try # on, off, or try + # (change requires restart) +#huge_page_size = 0 # zero for system default + # (change requires restart) +#temp_buffers = 8MB # min 800kB +#max_prepared_transactions = 0 # zero disables the feature + # (change requires restart) +# Caution: it is not advisable to set max_prepared_transactions nonzero unless +# you actively intend to use prepared transactions. +work_mem = {{ pgsql_work_mem }} +#hash_mem_multiplier = 1.0 # 1-1000.0 multiplier on hash table work_mem +maintenance_work_mem = {{ pgsql_maintenance_work_mem }} +#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem +#logical_decoding_work_mem = 64MB # min 64kB +#max_stack_depth = 2MB # min 100kB +#shared_memory_type = mmap # the default is the first option + # supported by the operating system: + # mmap + # sysv + # windows + # (change requires restart) +dynamic_shared_memory_type = posix # the default is the first option + # supported by the operating system: + # posix + # sysv + # windows + # mmap + # (change requires restart) +#min_dynamic_shared_memory = 0MB # (change requires restart) + +# - Disk - + +#temp_file_limit = -1 # limits per-process temp file space + # in kilobytes, or -1 for no limit + +# - Kernel Resources - + +#max_files_per_process = 1000 # min 64 + # (change requires restart) + +# - Cost-Based Vacuum Delay - + +#vacuum_cost_delay = 0 # 0-100 milliseconds (0 disables) +#vacuum_cost_page_hit = 1 # 0-10000 credits +#vacuum_cost_page_miss = 2 # 0-10000 credits +#vacuum_cost_page_dirty = 20 # 0-10000 credits +#vacuum_cost_limit = 200 # 1-10000 credits + +# - Background Writer - + +#bgwriter_delay = 200ms # 10-10000ms between rounds +#bgwriter_lru_maxpages = 100 # max buffers written/round, 0 disables +#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round +#bgwriter_flush_after = 512kB # measured in pages, 0 disables + +# - Asynchronous Behavior - + +#backend_flush_after = 0 # measured in pages, 0 disables +effective_io_concurrency = {{ pgsql_effective_io_concurrency }} +#maintenance_io_concurrency = 10 # 1-1000; 0 disables prefetching +max_worker_processes = {{ pgsql_max_worker_processes }} +max_parallel_workers_per_gather = {{ pgsql_max_parallel_workers_per_gather }} +max_parallel_maintenance_workers = {{ pgsql_max_parallel_maintenance_workers }} +max_parallel_workers = {{ pgsql_max_parallel_workers }} +#parallel_leader_participation = on +#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate + # (change requires restart) + + +#------------------------------------------------------------------------------ +# WRITE-AHEAD LOG +#------------------------------------------------------------------------------ + +# - Settings - + +#wal_level = replica # minimal, replica, or logical + # (change requires restart) +#fsync = on # flush data to disk for crash safety + # (turning this off can cause + # unrecoverable data corruption) +#synchronous_commit = on # synchronization level; + # off, local, remote_write, remote_apply, or on +#wal_sync_method = fsync # the default is the first option + # supported by the operating system: + # open_datasync + # fdatasync (default on Linux and FreeBSD) + # fsync + # fsync_writethrough + # open_sync +#full_page_writes = on # recover from partial page writes +#wal_log_hints = off # also do full page writes of non-critical updates + # (change requires restart) +#wal_compression = off # enable compression of full-page writes +#wal_init_zero = on # zero-fill new WAL files +#wal_recycle = on # recycle WAL files +wal_buffers = {{ pgsql_wal_buffers }} + # (change requires restart) +#wal_writer_delay = 200ms # 1-10000 milliseconds +#wal_writer_flush_after = 1MB # measured in pages, 0 disables +#wal_skip_threshold = 2MB + +#commit_delay = 0 # range 0-100000, in microseconds +#commit_siblings = 5 # range 1-1000 + +# - Checkpoints - + +#checkpoint_timeout = 5min # range 30s-1d +checkpoint_completion_target = {{ pgsql_checkpoint_completion_target }} +#checkpoint_flush_after = 256kB # measured in pages, 0 disables +#checkpoint_warning = 30s # 0 disables +min_wal_size = {{ pgsql_min_wal_size }} +max_wal_size = {{ pgsql_max_wal_size }} + +# - Archiving - + +#archive_mode = off # enables archiving; off, on, or always + # (change requires restart) +#archive_command = '' # command to use to archive a logfile segment + # placeholders: %p = path of file to archive + # %f = file name only + # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' +#archive_timeout = 0 # force a logfile segment switch after this + # number of seconds; 0 disables + +# - Archive Recovery - + +# These are only used in recovery mode. + +#restore_command = '' # command to use to restore an archived logfile segment + # placeholders: %p = path of file to restore + # %f = file name only + # e.g. 'cp /mnt/server/archivedir/%f %p' +#archive_cleanup_command = '' # command to execute at every restartpoint +#recovery_end_command = '' # command to execute at completion of recovery + +# - Recovery Target - + +# Set these only when performing a targeted recovery. + +#recovery_target = '' # 'immediate' to end recovery as soon as a + # consistent state is reached + # (change requires restart) +#recovery_target_name = '' # the named restore point to which recovery will proceed + # (change requires restart) +#recovery_target_time = '' # the time stamp up to which recovery will proceed + # (change requires restart) +#recovery_target_xid = '' # the transaction ID up to which recovery will proceed + # (change requires restart) +#recovery_target_lsn = '' # the WAL LSN up to which recovery will proceed + # (change requires restart) +#recovery_target_inclusive = on # Specifies whether to stop: + # just after the specified recovery target (on) + # just before the recovery target (off) + # (change requires restart) +#recovery_target_timeline = 'latest' # 'current', 'latest', or timeline ID + # (change requires restart) +#recovery_target_action = 'pause' # 'pause', 'promote', 'shutdown' + # (change requires restart) + + +#------------------------------------------------------------------------------ +# REPLICATION +#------------------------------------------------------------------------------ + +# - Sending Servers - + +# Set these on the primary and on any standby that will send replication data. + +#max_wal_senders = 10 # max number of walsender processes + # (change requires restart) +#max_replication_slots = 10 # max number of replication slots + # (change requires restart) +#wal_keep_size = 0 # in megabytes; 0 disables +#max_slot_wal_keep_size = -1 # in megabytes; -1 disables +#wal_sender_timeout = 60s # in milliseconds; 0 disables +#track_commit_timestamp = off # collect timestamp of transaction commit + # (change requires restart) + +# - Primary Server - + +# These settings are ignored on a standby server. + +#synchronous_standby_names = '' # standby servers that provide sync rep + # method to choose sync standbys, number of sync standbys, + # and comma-separated list of application_name + # from standby(s); '*' = all +#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed + +# - Standby Servers - + +# These settings are ignored on a primary server. + +#primary_conninfo = '' # connection string to sending server +#primary_slot_name = '' # replication slot on sending server +#promote_trigger_file = '' # file name whose presence ends recovery +#hot_standby = on # "off" disallows queries during recovery + # (change requires restart) +#max_standby_archive_delay = 30s # max delay before canceling queries + # when reading WAL from archive; + # -1 allows indefinite delay +#max_standby_streaming_delay = 30s # max delay before canceling queries + # when reading streaming WAL; + # -1 allows indefinite delay +#wal_receiver_create_temp_slot = off # create temp slot if primary_slot_name + # is not set +#wal_receiver_status_interval = 10s # send replies at least this often + # 0 disables +#hot_standby_feedback = off # send info from standby to prevent + # query conflicts +#wal_receiver_timeout = 60s # time that receiver waits for + # communication from primary + # in milliseconds; 0 disables +#wal_retrieve_retry_interval = 5s # time to wait before retrying to + # retrieve WAL after a failed attempt +#recovery_min_apply_delay = 0 # minimum delay for applying changes during recovery + +# - Subscribers - + +# These settings are ignored on a publisher. + +#max_logical_replication_workers = 4 # taken from max_worker_processes + # (change requires restart) +#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers + + +#------------------------------------------------------------------------------ +# QUERY TUNING +#------------------------------------------------------------------------------ + +# - Planner Method Configuration - + +#enable_async_append = on +#enable_bitmapscan = on +#enable_gathermerge = on +#enable_hashagg = on +#enable_hashjoin = on +#enable_incremental_sort = on +#enable_indexscan = on +#enable_indexonlyscan = on +#enable_material = on +#enable_memoize = on +#enable_mergejoin = on +#enable_nestloop = on +#enable_parallel_append = on +#enable_parallel_hash = on +#enable_partition_pruning = on +#enable_partitionwise_join = off +#enable_partitionwise_aggregate = off +#enable_seqscan = on +#enable_sort = on +#enable_tidscan = on + +# - Planner Cost Constants - + +#seq_page_cost = 1.0 # measured on an arbitrary scale +random_page_cost = {{ pgsql_random_page_cost }} + # same scale as above +#cpu_tuple_cost = 0.01 # same scale as above +#cpu_index_tuple_cost = 0.005 # same scale as above +#cpu_operator_cost = 0.0025 # same scale as above +#parallel_setup_cost = 1000.0 # same scale as above +#parallel_tuple_cost = 0.1 # same scale as above +#min_parallel_table_scan_size = 8MB +#min_parallel_index_scan_size = 512kB +effective_cache_size = {{ pgsql_effective_cache_size }} + +#jit_above_cost = 100000 # perform JIT compilation if available + # and query more expensive than this; + # -1 disables +#jit_inline_above_cost = 500000 # inline small functions if query is + # more expensive than this; -1 disables +#jit_optimize_above_cost = 500000 # use expensive JIT optimizations if + # query is more expensive than this; + # -1 disables + +# - Genetic Query Optimizer - + +#geqo = on +#geqo_threshold = 12 +#geqo_effort = 5 # range 1-10 +#geqo_pool_size = 0 # selects default based on effort +#geqo_generations = 0 # selects default based on effort +#geqo_selection_bias = 2.0 # range 1.5-2.0 +#geqo_seed = 0.0 # range 0.0-1.0 + +# - Other Planner Options - + +default_statistics_target = {{ pgsql_default_statistics_target }} +#constraint_exclusion = partition # on, off, or partition +#cursor_tuple_fraction = 0.1 # range 0.0-1.0 +#from_collapse_limit = 8 +#jit = on # allow JIT compilation +#join_collapse_limit = 8 # 1 disables collapsing of explicit + # JOIN clauses +#plan_cache_mode = auto # auto, force_generic_plan or + # force_custom_plan + + +#------------------------------------------------------------------------------ +# REPORTING AND LOGGING +#------------------------------------------------------------------------------ + +# - Where to Log - + +#log_destination = 'stderr' # Valid values are combinations of + # stderr, csvlog, syslog, and eventlog, + # depending on platform. csvlog + # requires logging_collector to be on. + +# This is used when logging to stderr: +#logging_collector = off # Enable capturing of stderr and csvlog + # into log files. Required to be on for + # csvlogs. + # (change requires restart) + +# These are only used if logging_collector is on: +#log_directory = 'log' # directory where log files are written, + # can be absolute or relative to PGDATA +#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern, + # can include strftime() escapes +#log_file_mode = 0600 # creation mode for log files, + # begin with 0 to use octal notation +#log_rotation_age = 1d # Automatic rotation of logfiles will + # happen after that time. 0 disables. +#log_rotation_size = 10MB # Automatic rotation of logfiles will + # happen after that much log output. + # 0 disables. +#log_truncate_on_rotation = off # If on, an existing log file with the + # same name as the new log file will be + # truncated rather than appended to. + # But such truncation only occurs on + # time-driven rotation, not on restarts + # or size-driven rotation. Default is + # off, meaning append to existing files + # in all cases. + +# These are relevant when logging to syslog: +#syslog_facility = 'LOCAL0' +#syslog_ident = 'postgres' +#syslog_sequence_numbers = on +#syslog_split_messages = on + +# This is only relevant when logging to eventlog (Windows): +# (change requires restart) +#event_source = 'PostgreSQL' + +# - When to Log - + +#log_min_messages = warning # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic + +#log_min_error_statement = error # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic (effectively off) + +#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements + # and their durations, > 0 logs only + # statements running at least this number + # of milliseconds + +#log_min_duration_sample = -1 # -1 is disabled, 0 logs a sample of statements + # and their durations, > 0 logs only a sample of + # statements running at least this number + # of milliseconds; + # sample fraction is determined by log_statement_sample_rate + +#log_statement_sample_rate = 1.0 # fraction of logged statements exceeding + # log_min_duration_sample to be logged; + # 1.0 logs all such statements, 0.0 never logs + + +#log_transaction_sample_rate = 0.0 # fraction of transactions whose statements + # are logged regardless of their duration; 1.0 logs all + # statements from all transactions, 0.0 never logs + +# - What to Log - + +#debug_print_parse = off +#debug_print_rewritten = off +#debug_print_plan = off +#debug_pretty_print = on +#log_autovacuum_min_duration = -1 # log autovacuum activity; + # -1 disables, 0 logs all actions and + # their durations, > 0 logs only + # actions running at least this number + # of milliseconds. +#log_checkpoints = off +#log_connections = off +#log_disconnections = off +#log_duration = off +#log_error_verbosity = default # terse, default, or verbose messages +#log_hostname = off +log_line_prefix = '%m [%p] %q%u@%d ' # special values: + # %a = application name + # %u = user name + # %d = database name + # %r = remote host and port + # %h = remote host + # %b = backend type + # %p = process ID + # %P = process ID of parallel group leader + # %t = timestamp without milliseconds + # %m = timestamp with milliseconds + # %n = timestamp with milliseconds (as a Unix epoch) + # %Q = query ID (0 if none or not computed) + # %i = command tag + # %e = SQL state + # %c = session ID + # %l = session line number + # %s = session start timestamp + # %v = virtual transaction ID + # %x = transaction ID (0 if none) + # %q = stop here in non-session + # processes + # %% = '%' + # e.g. '<%u%%%d> ' +#log_lock_waits = off # log lock waits >= deadlock_timeout +#log_recovery_conflict_waits = off # log standby recovery conflict waits + # >= deadlock_timeout +#log_parameter_max_length = -1 # when logging statements, limit logged + # bind-parameter values to N bytes; + # -1 means print in full, 0 disables +#log_parameter_max_length_on_error = 0 # when logging an error, limit logged + # bind-parameter values to N bytes; + # -1 means print in full, 0 disables +#log_statement = 'none' # none, ddl, mod, all +#log_replication_commands = off +#log_temp_files = -1 # log temporary files equal or larger + # than the specified size in kilobytes; + # -1 disables, 0 logs all temp files +log_timezone = 'Europe/Berlin' + + +#------------------------------------------------------------------------------ +# PROCESS TITLE +#------------------------------------------------------------------------------ + +cluster_name = '14/main' # added to process titles if nonempty + # (change requires restart) +#update_process_title = on + + +#------------------------------------------------------------------------------ +# STATISTICS +#------------------------------------------------------------------------------ + +# - Query and Index Statistics Collector - + +#track_activities = on +#track_activity_query_size = 1024 # (change requires restart) +#track_counts = on +#track_io_timing = off +#track_wal_io_timing = off +#track_functions = none # none, pl, all +stats_temp_directory = '/var/run/postgresql/14-main.pg_stat_tmp' + + +# - Monitoring - + +#compute_query_id = auto +#log_statement_stats = off +#log_parser_stats = off +#log_planner_stats = off +#log_executor_stats = off + + +#------------------------------------------------------------------------------ +# AUTOVACUUM +#------------------------------------------------------------------------------ + +#autovacuum = on # Enable autovacuum subprocess? 'on' + # requires track_counts to also be on. +#autovacuum_max_workers = 3 # max number of autovacuum subprocesses + # (change requires restart) +#autovacuum_naptime = 1min # time between autovacuum runs +#autovacuum_vacuum_threshold = 50 # min number of row updates before + # vacuum +#autovacuum_vacuum_insert_threshold = 1000 # min number of row inserts + # before vacuum; -1 disables insert + # vacuums +#autovacuum_analyze_threshold = 50 # min number of row updates before + # analyze +#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum +#autovacuum_vacuum_insert_scale_factor = 0.2 # fraction of inserts over table + # size before insert vacuum +#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze +#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum + # (change requires restart) +#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age + # before forced vacuum + # (change requires restart) +#autovacuum_vacuum_cost_delay = 2ms # default vacuum cost delay for + # autovacuum, in milliseconds; + # -1 means use vacuum_cost_delay +#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for + # autovacuum, -1 means use + # vacuum_cost_limit + + +#------------------------------------------------------------------------------ +# CLIENT CONNECTION DEFAULTS +#------------------------------------------------------------------------------ + +# - Statement Behavior - + +#client_min_messages = notice # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # log + # notice + # warning + # error +#search_path = '"$user", public' # schema names +#row_security = on +#default_table_access_method = 'heap' +#default_tablespace = '' # a tablespace name, '' uses the default +#default_toast_compression = 'pglz' # 'pglz' or 'lz4' +#temp_tablespaces = '' # a list of tablespace names, '' uses + # only default tablespace +#check_function_bodies = on +#default_transaction_isolation = 'read committed' +#default_transaction_read_only = off +#default_transaction_deferrable = off +#session_replication_role = 'origin' +#statement_timeout = 0 # in milliseconds, 0 is disabled +#lock_timeout = 0 # in milliseconds, 0 is disabled +#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled +#idle_session_timeout = 0 # in milliseconds, 0 is disabled +#vacuum_freeze_table_age = 150000000 +#vacuum_freeze_min_age = 50000000 +#vacuum_failsafe_age = 1600000000 +#vacuum_multixact_freeze_table_age = 150000000 +#vacuum_multixact_freeze_min_age = 5000000 +#vacuum_multixact_failsafe_age = 1600000000 +#bytea_output = 'hex' # hex, escape +#xmlbinary = 'base64' +#xmloption = 'content' +#gin_pending_list_limit = 4MB + +# - Locale and Formatting - + +datestyle = 'iso, mdy' +#intervalstyle = 'postgres' +timezone = 'Europe/Berlin' +#timezone_abbreviations = 'Default' # Select the set of available time zone + # abbreviations. Currently, there are + # Default + # Australia (historical usage) + # India + # You can create your own file in + # share/timezonesets/. +#extra_float_digits = 1 # min -15, max 3; any value >0 actually + # selects precise output mode +#client_encoding = sql_ascii # actually, defaults to database + # encoding + +# These settings are initialized by initdb, but they can be changed. +lc_messages = 'en_US.UTF-8' # locale for system error message + # strings +lc_monetary = 'en_US.UTF-8' # locale for monetary formatting +lc_numeric = 'en_US.UTF-8' # locale for number formatting +lc_time = 'en_US.UTF-8' # locale for time formatting + +# default configuration for text search +default_text_search_config = 'pg_catalog.english' + +# - Shared Library Preloading - + +#local_preload_libraries = '' +#session_preload_libraries = '' +#shared_preload_libraries = '' # (change requires restart) +#jit_provider = 'llvmjit' # JIT library to use + +# - Other Defaults - + +#dynamic_library_path = '$libdir' +#extension_destdir = '' # prepend path when loading extensions + # and shared objects (added by Debian) +#gin_fuzzy_search_limit = 0 + + +#------------------------------------------------------------------------------ +# LOCK MANAGEMENT +#------------------------------------------------------------------------------ + +#deadlock_timeout = 1s +#max_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_relation = -2 # negative values mean + # (max_pred_locks_per_transaction + # / -max_pred_locks_per_relation) - 1 +#max_pred_locks_per_page = 2 # min 0 + + +#------------------------------------------------------------------------------ +# VERSION AND PLATFORM COMPATIBILITY +#------------------------------------------------------------------------------ + +# - Previous PostgreSQL Versions - + +#array_nulls = on +#backslash_quote = safe_encoding # on, off, or safe_encoding +#escape_string_warning = on +#lo_compat_privileges = off +#quote_all_identifiers = off +#standard_conforming_strings = on +#synchronize_seqscans = on + +# - Other Platforms and Clients - + +#transform_null_equals = off + + +#------------------------------------------------------------------------------ +# ERROR HANDLING +#------------------------------------------------------------------------------ + +#exit_on_error = off # terminate session on any error? +#restart_after_crash = on # reinitialize after backend crash? +#data_sync_retry = off # retry or panic on failure to fsync + # data? + # (change requires restart) +#recovery_init_sync_method = fsync # fsync, syncfs (Linux 5.8+) + + +#------------------------------------------------------------------------------ +# CONFIG FILE INCLUDES +#------------------------------------------------------------------------------ + +# These options allow settings to be loaded from files other than the +# default postgresql.conf. Note that these are directives, not variable +# assignments, so they can usefully be given more than once. + +include_dir = 'conf.d' # include files ending in '.conf' from + # a directory, e.g., 'conf.d' +#include_if_exists = '...' # include file only if it exists +#include = '...' # include file + + +#------------------------------------------------------------------------------ +# CUSTOMIZED OPTIONS +#------------------------------------------------------------------------------ + +# Add settings for extensions here \ No newline at end of file diff --git a/roles/postgresql/vars/main.yml b/roles/postgresql/vars/main.yml new file mode 100644 index 0000000..dac11c0 --- /dev/null +++ b/roles/postgresql/vars/main.yml @@ -0,0 +1,31 @@ +--- +pgsql_server_version: 14 +pgsql_unix_socket: "/var/run/postgresql" # comma-separated list of directories +pgsql_listen_addresses: "{{ pgsql_server_ip }}" # what IP address(es) to listen on; +pgsql_password_encryption: "scram-sha-256" # scram-sha-256 or md5 +pgsql_max_connections: "200" # default 100 +pgsql_shared_buffers: "1GB" # min 128kB, default 128MB +pgsql_effective_cache_size: "3GB" # default 4GB +pgsql_maintenance_work_mem: "256MB" # min 1MB, default 64MB +pgsql_checkpoint_completion_target: "0.9" # checkpoint target duration, 0.0 - 1.0, default 0.9 +pgsql_wal_buffers: "16MB" # min 32kB, default -1 sets based on shared_buffers +pgsql_default_statistics_target: "100" # range 1-10000, default 100 +pgsql_random_page_cost: "1.1" # how long it take to seek to a random disk page, default 4.0 +pgsql_effective_io_concurrency: "200" # 1-1000; 0 disables prefetching, default 1 +pgsql_work_mem: "5242kB" # min 64kB, default 4MB +pgsql_min_wal_size: "1GB" # default 80MB +pgsql_max_wal_size: "4GB" # default 1GB +pgsql_max_worker_processes: "2" # default 8 +pgsql_max_parallel_workers_per_gather: "1" # taken from max_parallel_workers, default 2 +pgsql_max_parallel_workers: "2" # maximum number of max_worker_processes that can be used in parallel, default 8 +pgsql_max_parallel_maintenance_workers: "1" # taken from max_parallel_workers, default 2 + +pgsql_exporter_install_dir: "/usr/local/bin" +pgsql_exporter_user: "postgres" + +pgsql_client_auth: + - name: nextcloud + db: nextcloud_db + user: nextcloud_db_user + address: "{{ nextcloud_server_ip }}/32" + method: scram-sha-256 diff --git a/roles/rclone/defaults/main.yml b/roles/rclone/defaults/main.yml new file mode 100644 index 0000000..b008b15 --- /dev/null +++ b/roles/rclone/defaults/main.yml @@ -0,0 +1,3 @@ +--- +# rclone config file changes while using to force update set this "true" +rclone_config_force: false diff --git a/roles/rclone/files/DTSV_GD_service_account.json b/roles/rclone/files/DTSV_GD_service_account.json new file mode 100644 index 0000000..02f8e2f --- /dev/null +++ b/roles/rclone/files/DTSV_GD_service_account.json @@ -0,0 +1,121 @@ +$ANSIBLE_VAULT;1.2;AES256;dtsv-dev +62646235323433313363376439333961373139613464323833366263656433653761323133656437 +3331326266643131386336303465646162303962353339310a653330316264613462623963646536 +32303364353236346261303263303965326537663863653436653161383239613165306263653036 +6632356336313634330a396433303036323563653838333537373661326333623936306638333932 +38616239383462653062643031663361646463343930303265626136393635353835313339313939 +62626236373735343530366530613062306463393565613561643632323966663965613034623932 +35373438643739383832393333383732393963666136396537316163353135316233636638626666 +64343639376665623131343464353266623234666135663864333234366666326563386264373539 +31643231313437363135613965396339663762656466396433313335303561383864356533636264 +61363330633464353839353264613338306133623565663835636632626636356662643032396466 +39663336353738363662313833366530336334646462656432306439396136383762303537343532 +33396261353835376163366337393937363761323965356538393561343639363132353762373531 +35656532363631353531613231353435663862333366663565663838383536633666653332636262 +31643562363337393038636163333265663834306330393830353262386634336135636436323431 +62353338326430313662373962333733656434336138376466336534383963346261636233653232 +62643165383034386233376263333533666162346531623362313337666362356136313266613937 +34373266323034653736666163316135633261303037376632623266366333336635306461636536 +34386633636230663663383565623861326665373062636339663566313433633930656161373134 +35373464643738346366643338373534373163393962393266393936313433653863303066373530 +61303163666162356561623930313636303836383131323230356564306334393161303263333966 +36636361323037366539363338666537633134326561656666613764323266363432656235343931 +36653566373330643762646435656266663333323336366434393066303839653039643064343862 +64366434396564643064316439383438333633623539333338353862663136656539336139343863 +64643234353162376237626563663339633332303535303133313064336433623662393762643032 +33343062653539306539373437326161343461623331666531343138616331393439613361626561 +32653133366633326236636561366433646631656434396365383736616235666539313562653863 +64306332393361353831333562356232656432323138623637653731323030613062343830646665 +63333937666635393039393337313332663834336330643138383338623336633930653532363862 +33663237343939666236663333363765326261616566663765353231643936653036353434613164 +31643233626130303864343961663737326432353230336135393230373066613536353833343932 +62303631623630356636386163663362613432316531353865653639366339316230396238366635 +37636637633032316466663133343664643761303735666365616531643034323365613932633364 +36316562366365373231373235303634646566393731326662343136343130306239333534326230 +39373764663232343135323366333862336164653439363538316234313365643035636133383561 +37336361373961373866353430646337643661303035323837383433633033346134633839623865 +65636333666664346436356235333831303336386531653835326439626665666162653262613366 +39373262623238326430376163356232343763383762643163383932663934336535316465386132 +34363331666563393236613331663463333665363337653162306630666638326565626431636166 +38343631343664626135653638323733393562373435633939316563613131636535343833366638 +66323363393536363938623634656134356531373835646339373437353432373435636134303835 +33376461393835363661373761383463666264353933636231643232633565373636376335623964 +34356530323236666538363861333939306362666133323636313636336433636332386130346331 +34313862643132386166613765646466303035333136353837393130626330346262313335313362 +62373262666137366235363533376366316435653835303334613436613763663732363635656663 +37623962373766666338313864623632663166343730386530333266616430366233393138653563 +64363438333565646137643065386234333064643036656165666535646239333961396530646163 +61353436343134663539663036653863353636353861373836326362643562623030616637376536 +63303761313166323336393963343938366632386339366633363061336139333432366431346533 +61363934656239396631626530613639646634306436346561616534313738623035323537343330 +36366133363235653535656465663531383236653165346130366439356535633435663239313763 +35326532616365646163653262393333303535623937636631383665303230626266666562363563 +32326164323930396633366539323033656230386263616230323532626366333530386335303166 +37653930366262343630326365396262393231633237653138343664633165666531616631653530 +66316230396362363565646338383461663765633865666231366265363962623636363932356436 +63306564666361346439386161386166633934326631656665363839653665633465653365646238 +30323162396433346630383965666436643465333332633962343931393534326539626335343237 +36333763656364376164613639663862666263663237623237393232323963396233373930316238 +31626530353037386362373637626334616239316534653166366237336263633362626238656664 +61613931303036353164623538323432303761303163633635633730663836653333643433393937 +63666136356134393764386163646266323863393236646532613533373133663164363937376230 +31316433333564666662393563303365376562363932343963333462383139336135356666636238 +62653664323238646162633636336539373237613661666330626336626632633139393934653537 +65623335313931623439326634393065303736396134386236353134363263353031336331376664 +66646139646565323465343332623936613735626663653264633064633564373133353037656263 +39656635666232653138663738636661643566326539613364636535323435363139656238333531 +64326636656263303733623031643164653733646137396461396338373866383931626637633066 +62363530303965383464643536323065373238626232646564363566366463376566303632346137 +37363936346130383439663062613236646336653861316462396437383466346363643062323834 +36643034336434646331313764376237636464383165326136656363356236333936623834653934 +36666561333463663937363231386662646261653365636264336265373264663766626265623330 +66346436633235343761663963323533393534363034323135333832353738346435653734333766 +32633435666537633961626533636436653766353066633461353561636262643965363432316235 +65303536316531653463306432646631353535356335623532643730353030373261343836663066 +36353831366231633363396336663666303465303138326537383863616662623637383832636166 +66326536633062626135636530386466386235666462343462393966373637653166643539356235 +66333531613636373733643831396339376162313335313436303531303264393537326231663865 +30383464326230633639366236316265353262306235383734383462353562383433396565373937 +30306662346663373464383038626666333761346162343133343262613164316137323162613035 +63623335373738356538396537386533306537633237616332643962363632383532376237383332 +31393632386333633939363737353531623637346336636135623162303131613538666561343734 +30306437656462346238363839303334613366643031356366323133373663393037323236353834 +65663239633333383066393332336230333337656239313732633962386437336362383564343963 +34303038666132383339373631346666336434333133393432316631363236633734623838643965 +66656238303335393630623033366236326435616537303862353464376561373832373663356532 +39313236646130646266316633336265396132323730313136386436656263663035646534346364 +30626330396432366230386534623839663339376134323639323433383666383035373136613037 +65303330636265353135373066656265373539623839323732653832303562643966386232373566 +64646161326461356533616366653966633638326431306433393739656463316430383664356163 +39643433316136633030333461303362623861396136626433303736326436336539616330613831 +64626133303561333263653331323631343861323530353937333538366466333539373937393732 +65313231336332396463633364663264346430613964363561396339613230303962643834393731 +35656663313335373331396430363062353834636232303165306566633461326533653665636431 +38333563636666643930376235656663303638653134666466376533396639343131306633656331 +35303566363466363362373138343966346339313963613330336337323831353733386531363263 +32343237346332613536353834613163386333313937323739333638336561363431363135393036 +32313863323730343765356437366466393262326535356266313734656664346663663635393639 +34383739613536613931376637373238323139326533333631653963343131663431663639383733 +62316535633337333439363835326435393338313061666335343837353839663133343230326134 +65353935656233613634633162313761376363323438346432613630346662313834323964383163 +30636339633066643666343532306332343338333135373334306537636665353936363833363964 +38396561396463313230656531333632313532623735393935643532663764643533646636313230 +61613766366235303639643031623464396138653463333438356134366361613739366235663136 +61386362663437663266323762363034396132383935353831336436626432303732393731336265 +61343863376237363562353834333862613130373330316333323838396636663631366666653832 +31343534316162356662623563373164326239396361623766366139316630333666346237326162 +38353631633630333139323661666132643035626263633533343766636330336434326131633438 +63303465653531643130393631363432653362393339366536323936666661343639306537383764 +38393739366665633332633062383134383263646138346437613964663233636134326431616639 +63613464353666306363613437353033646362343134646337323935616330353834666138356263 +37656236373833326665633531663537623662343439383263393566643463313437376466303039 +39356463633438656166313036383739306166646663363762333333636338646134323234333034 +33383834633231346533323333326432643464323063363063383665306133663862343230333135 +61366332343464306362643732613635653239306234373665303863326437373962393639616265 +32326638636638393335383734346331323932333030306139386138303935346438306631343836 +31646432393830303662376466353632646564343361393635373436313231393866363931613161 +39636233366465653638356236373232323633636339646162353239323130323437613736346236 +62616235633831616561386666626264326434383534356637363335363039646530653839646539 +35386136396634636264666536383662363366666530626163623835363935353238306133633666 +64633136663634393066623134653738666563363337303039386465393961313637643934393939 +38373632646234393430 diff --git a/roles/rclone/files/set-rclone-password b/roles/rclone/files/set-rclone-password new file mode 100644 index 0000000..783773c --- /dev/null +++ b/roles/rclone/files/set-rclone-password @@ -0,0 +1,4 @@ +#!/bin/echo Source this file don't run it + +read -s -p "Password: " RCLONE_CONFIG_PASS +export RCLONE_CONFIG_PASS \ No newline at end of file diff --git a/roles/rclone/tasks/main.yml b/roles/rclone/tasks/main.yml new file mode 100644 index 0000000..c29b783 --- /dev/null +++ b/roles/rclone/tasks/main.yml @@ -0,0 +1,90 @@ +--- + +# Get latest Rclone version via downloads.rclone.org/version.txt +- name: Check latest stable rclone version + uri: + url: https://downloads.rclone.org/version.txt + return_content: true + delegate_to: localhost + run_once: true + register: + rclone_version +- name: "{{ rclone_version.content }}" + set_fact: + rclone_version: "{{ rclone_version.content | replace ('rclone v', '', 1) | trim }}" + run_once: true + +- name: "Install rclone {{ rclone_version }}" + apt: + deb: "https://downloads.rclone.org/v{{ rclone_version }}/rclone-v{{ rclone_version }}-linux-{{ deb_architecture }}.deb" + register: _install_package + until: _install_package is succeeded + retries: 3 + delay: 5 + +- name: Symlink rclone binary to use mount helper + file: + src: "/usr/bin/rclone" + dest: "/sbin/mount.rclone" + state: link + +- name: Create rclone config directory + file: + path: "{{ rclone_config_dir }}" + state: directory + mode: 700 + +- name: Create rclone group + group: + name: "{{ rclone_system_group }}" + state: present + system: true + register: created_rclone_group + when: rclone_system_group != "root" + +- name: Create rclone user + user: + name: "{{ rclone_system_user }}" + group: "{{ rclone_system_group }}" + groups: "{{ rclone_system_group }}" + append: true + shell: /usr/sbin/nologin + system: true + create_home: false + home: / + register: created_rclone_user + +- name: adding existing user {{ main_user }} to group rclone + user: + name: "{{ main_user }}" + groups: "{{ rclone_system_group }}" + append: true + +- name: Create rclone cache/log directory + file: + path: "{{ item }}" + mode: 0755 + state: directory + loop: + - "{{ rclone_cache_dir }}" + - "{{ rclone_log_dir }}" + +- name: Copy rclone logrotate file + template: + src: logrotate.rclone.j2 + dest: /etc/logrotate.d/rclone + mode: 0644 + +- name: Copy service account files + copy: + src: "{{ item }}" + dest: "{{ rclone_config_dir }}/{{ item }}" + mode: 0600 + loop: + - DTSV_GD_service_account.json + +- name: Copy config password script + copy: + src: set-rclone-password + dest: ~/set-rclone-password + mode: 0644 diff --git a/roles/rclone/templates/logrotate.rclone.j2 b/roles/rclone/templates/logrotate.rclone.j2 new file mode 100644 index 0000000..7043038 --- /dev/null +++ b/roles/rclone/templates/logrotate.rclone.j2 @@ -0,0 +1,10 @@ +## Managed by Ansible ## + +{{ rclone_log_dir }}/*.log { + rotate 3 + copytruncate + daily + compress + missingok + notifempty +} \ No newline at end of file diff --git a/roles/rclone/vars/main.yml b/roles/rclone/vars/main.yml new file mode 100644 index 0000000..ff0fd1e --- /dev/null +++ b/roles/rclone/vars/main.yml @@ -0,0 +1,51 @@ +--- + +rclone_system_group: "rclone" +rclone_system_user: "{{ rclone_system_group }}" +rclone_config_dir: "/root/.config/rclone" +rclone_config_file: "{{ rclone_config_dir }}/rclone.conf" +rclone_cache_dir: "/var/cache/rclone" +rclone_log_dir: "/var/log/rclone" +rclone_user_agent_gd: 'GoogleDriveFS/64.0.4.0 (Windows;OSVer=10.0.22621;)' + +vault_gd3_crypt_password: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 37663062636264363661343664303536653930393430353735366135633739333732353937666362 + 3164313666363530643666303430326334326462393665390a363831326239363032323939613732 + 30376330313164633131313761343735313333653866623931343762643333666136626137383862 + 3030666263616663370a636634666565333638353634363463326630306462646137343231656663 + 39313938373366623461636666393432333663663134396334353931353465393137366665363165 + 64353236376133396364656561333962636635623832366461303831346338666364353239316634 + 356138346235666165653061313636346364 +vault_gd3_crypt_password2: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 30383339356132613064653366633531663963343665636439343862653965366662353836646633 + 6634346435313962396365396338633032663937616361370a386531663266353732643561346464 + 35373664356335313363333265326461653430333236623932646362393439393462616533303063 + 6431393236303662650a393434346137393564663765376161386234363063313463663066313630 + 36666336303537663036656463316239346563393365373664323538663864303463346535316331 + 66383034653464303861393333623833393261646138653531396461313166366132343539383238 + 386631653433313336636339363839316266 + +# Rclone Service Account Block +DTSV_GD_service_account_remote: | + [GD3] + type = drive + scope = drive + server_side_across_configs = true + service_account_file = {{ rclone_config_dir }}/DTSV_GD_service_account.json + + [GD3_crypt] + type = crypt + remote = GD3:crypt + password = {{ vault_gd3_crypt_password }} + password2 = {{ vault_gd3_crypt_password2 }} + +# Rclone Exporter (same password see monitoring role) +vault_rclone_rcd_pass: !vault | + $ANSIBLE_VAULT;1.2;AES256;dtsv-dev + 34616137336639363734323532366663626166336638356538663534346530636564333066636337 + 6636626538653634383063616532393461393036383464620a613765363037306365666236396661 + 65356565383436383664356338333266353962396239316533303330626335303961383066633066 + 3032623266653639340a376361376361373235373939623137633630666333383237363138303933 + 66333735646465306165396536396166616462633766333732323965363566656132 diff --git a/roles/redis/defaults/main.yml b/roles/redis/defaults/main.yml new file mode 100644 index 0000000..43fef26 --- /dev/null +++ b/roles/redis/defaults/main.yml @@ -0,0 +1,4 @@ +--- + +# If port 0 is specified Redis will not listen on a TCP socket. +redis_port: 0 diff --git a/roles/redis/handlers/main.yml b/roles/redis/handlers/main.yml new file mode 100644 index 0000000..a8c08cc --- /dev/null +++ b/roles/redis/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart redis + systemd: + name: redis-server.service + state: restarted diff --git a/roles/redis/tasks/main.yml b/roles/redis/tasks/main.yml new file mode 100644 index 0000000..ed8d044 --- /dev/null +++ b/roles/redis/tasks/main.yml @@ -0,0 +1,14 @@ +--- +- name: Install Redis + apt: + name: redis + state: present + +- name: Copy redis config + template: + src: redis.conf.j2 + dest: /etc/redis/redis.conf + owner: redis + group: redis + mode: 0640 + notify: restart redis diff --git a/roles/redis/templates/redis.conf.j2 b/roles/redis/templates/redis.conf.j2 new file mode 100644 index 0000000..c553871 --- /dev/null +++ b/roles/redis/templates/redis.conf.j2 @@ -0,0 +1,1055 @@ +## Managed by Ansible ## + +# Redis configuration file example. +# +# Note that in order to read the configuration file, Redis must be +# started with the file path as first argument: +# +# ./redis-server /path/to/redis.conf + +# Note on units: when memory size is needed, it is possible to specify +# it in the usual form of 1k 5GB 4M and so forth: +# +# 1k => 1000 bytes +# 1kb => 1024 bytes +# 1m => 1000000 bytes +# 1mb => 1024*1024 bytes +# 1g => 1000000000 bytes +# 1gb => 1024*1024*1024 bytes +# +# units are case insensitive so 1GB 1Gb 1gB are all the same. + +################################## INCLUDES ################################### + +# Include one or more other config files here. This is useful if you +# have a standard template that goes to all Redis servers but also need +# to customize a few per-server settings. Include files can include +# other files, so use this wisely. +# +# Notice option "include" won't be rewritten by command "CONFIG REWRITE" +# from admin or Redis Sentinel. Since Redis always uses the last processed +# line as value of a configuration directive, you'd better put includes +# at the beginning of this file to avoid overwriting config change at runtime. +# +# If instead you are interested in using includes to override configuration +# options, it is better to use include as the last line. +# +# include /path/to/local.conf +# include /path/to/other.conf + +################################## NETWORK ##################################### + +# By default, if no "bind" configuration directive is specified, Redis listens +# for connections from all the network interfaces available on the server. +# It is possible to listen to just one or multiple selected interfaces using +# the "bind" configuration directive, followed by one or more IP addresses. +# +# Examples: +# +# bind 192.168.1.1 +# bind 127.0.0.1 ::1 +# +# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the +# internet, binding to all the interfaces is dangerous and will expose the +# instance to everybody on the internet. So by default we uncomment the +# following bind directive, that will force Redis to listen only into +# the IPv4 lookback interface address (this means Redis will be able to +# accept connections only from clients running into the same computer it +# is running). +# +# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES +# JUST COMMENT THE FOLLOWING LINE. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bind 127.0.0.1 + +# Protected mode is a layer of security protection, in order to avoid that +# Redis instances left open on the internet are accessed and exploited. +# +# When protected mode is on and if: +# +# 1) The server is not binding explicitly to a set of addresses using the +# "bind" directive. +# 2) No password is configured. +# +# The server only accepts connections from clients connecting from the +# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain +# sockets. +# +# By default protected mode is enabled. You should disable it only if +# you are sure you want clients from other hosts to connect to Redis +# even if no authentication is configured, nor a specific set of interfaces +# are explicitly listed using the "bind" directive. +protected-mode yes + +# Accept connections on the specified port, default is 6379 (IANA #815344). +# If port 0 is specified Redis will not listen on a TCP socket. +port {{ redis_port }} + +# TCP listen() backlog. +# +# In high requests-per-second environments you need an high backlog in order +# to avoid slow clients connections issues. Note that the Linux kernel +# will silently truncate it to the value of /proc/sys/net/core/somaxconn so +# make sure to raise both the value of somaxconn and tcp_max_syn_backlog +# in order to get the desired effect. +tcp-backlog 511 + +# Unix socket. +# +# Specify the path for the Unix socket that will be used to listen for +# incoming connections. There is no default, so Redis will not listen +# on a unix socket when not specified. +# +unixsocket {{ redis_unixsocket }} +unixsocketperm {{ redis_unixsocketperm }} + +# Close the connection after a client is idle for N seconds (0 to disable) +timeout 0 + +# TCP keepalive. +# +# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence +# of communication. This is useful for two reasons: +# +# 1) Detect dead peers. +# 2) Take the connection alive from the point of view of network +# equipment in the middle. +# +# On Linux, the specified value (in seconds) is the period used to send ACKs. +# Note that to close the connection the double of the time is needed. +# On other kernels the period depends on the kernel configuration. +# +# A reasonable value for this option is 300 seconds, which is the new +# Redis default starting with Redis 3.2.1. +tcp-keepalive 300 + +################################# GENERAL ##################################### + +# By default Redis does not run as a daemon. Use 'yes' if you need it. +# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. +daemonize yes + +# If you run Redis from upstart or systemd, Redis can interact with your +# supervision tree. Options: +# supervised no - no supervision interaction +# supervised upstart - signal upstart by putting Redis into SIGSTOP mode +# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET +# supervised auto - detect upstart or systemd method based on +# UPSTART_JOB or NOTIFY_SOCKET environment variables +# Note: these supervision methods only signal "process is ready." +# They do not enable continuous liveness pings back to your supervisor. +supervised no + +# If a pid file is specified, Redis writes it where specified at startup +# and removes it at exit. +# +# When the server runs non daemonized, no pid file is created if none is +# specified in the configuration. When the server is daemonized, the pid file +# is used even if not specified, defaulting to "/var/run/redis.pid". +# +# Creating a pid file is best effort: if Redis is not able to create it +# nothing bad happens, the server will start and run normally. +pidfile /var/run/redis/redis-server.pid + +# Specify the server verbosity level. +# This can be one of: +# debug (a lot of information, useful for development/testing) +# verbose (many rarely useful info, but not a mess like the debug level) +# notice (moderately verbose, what you want in production probably) +# warning (only very important / critical messages are logged) +loglevel notice + +# Specify the log file name. Also the empty string can be used to force +# Redis to log on the standard output. Note that if you use standard +# output for logging but daemonize, logs will be sent to /dev/null +logfile /var/log/redis/redis-server.log + +# To enable logging to the system logger, just set 'syslog-enabled' to yes, +# and optionally update the other syslog parameters to suit your needs. +# syslog-enabled no + +# Specify the syslog identity. +# syslog-ident redis + +# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. +# syslog-facility local0 + +# Set the number of databases. The default database is DB 0, you can select +# a different one on a per-connection basis using SELECT where +# dbid is a number between 0 and 'databases'-1 +databases 16 + +################################ SNAPSHOTTING ################################ +# +# Save the DB on disk: +# +# save +# +# Will save the DB if both the given number of seconds and the given +# number of write operations against the DB occurred. +# +# In the example below the behaviour will be to save: +# after 900 sec (15 min) if at least 1 key changed +# after 300 sec (5 min) if at least 10 keys changed +# after 60 sec if at least 10000 keys changed +# +# Note: you can disable saving completely by commenting out all "save" lines. +# +# It is also possible to remove all the previously configured save +# points by adding a save directive with a single empty string argument +# like in the following example: +# +# save "" + +save 900 1 +save 300 10 +save 60 10000 + +# By default Redis will stop accepting writes if RDB snapshots are enabled +# (at least one save point) and the latest background save failed. +# This will make the user aware (in a hard way) that data is not persisting +# on disk properly, otherwise chances are that no one will notice and some +# disaster will happen. +# +# If the background saving process will start working again Redis will +# automatically allow writes again. +# +# However if you have setup your proper monitoring of the Redis server +# and persistence, you may want to disable this feature so that Redis will +# continue to work as usual even if there are problems with disk, +# permissions, and so forth. +stop-writes-on-bgsave-error yes + +# Compress string objects using LZF when dump .rdb databases? +# For default that's set to 'yes' as it's almost always a win. +# If you want to save some CPU in the saving child set it to 'no' but +# the dataset will likely be bigger if you have compressible values or keys. +rdbcompression yes + +# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. +# This makes the format more resistant to corruption but there is a performance +# hit to pay (around 10%) when saving and loading RDB files, so you can disable it +# for maximum performances. +# +# RDB files created with checksum disabled have a checksum of zero that will +# tell the loading code to skip the check. +rdbchecksum yes + +# The filename where to dump the DB +dbfilename dump.rdb + +# The working directory. +# +# The DB will be written inside this directory, with the filename specified +# above using the 'dbfilename' configuration directive. +# +# The Append Only File will also be created inside this directory. +# +# Note that you must specify a directory here, not a file name. +dir /var/lib/redis + +################################# REPLICATION ################################# + +# Master-Slave replication. Use slaveof to make a Redis instance a copy of +# another Redis server. A few things to understand ASAP about Redis replication. +# +# 1) Redis replication is asynchronous, but you can configure a master to +# stop accepting writes if it appears to be not connected with at least +# a given number of slaves. +# 2) Redis slaves are able to perform a partial resynchronization with the +# master if the replication link is lost for a relatively small amount of +# time. You may want to configure the replication backlog size (see the next +# sections of this file) with a sensible value depending on your needs. +# 3) Replication is automatic and does not need user intervention. After a +# network partition slaves automatically try to reconnect to masters +# and resynchronize with them. +# +# slaveof + +# If the master is password protected (using the "requirepass" configuration +# directive below) it is possible to tell the slave to authenticate before +# starting the replication synchronization process, otherwise the master will +# refuse the slave request. +# +# masterauth + +# When a slave loses its connection with the master, or when the replication +# is still in progress, the slave can act in two different ways: +# +# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will +# still reply to client requests, possibly with out of date data, or the +# data set may just be empty if this is the first synchronization. +# +# 2) if slave-serve-stale-data is set to 'no' the slave will reply with +# an error "SYNC with master in progress" to all the kind of commands +# but to INFO and SLAVEOF. +# +slave-serve-stale-data yes + +# You can configure a slave instance to accept writes or not. Writing against +# a slave instance may be useful to store some ephemeral data (because data +# written on a slave will be easily deleted after resync with the master) but +# may also cause problems if clients are writing to it because of a +# misconfiguration. +# +# Since Redis 2.6 by default slaves are read-only. +# +# Note: read only slaves are not designed to be exposed to untrusted clients +# on the internet. It's just a protection layer against misuse of the instance. +# Still a read only slave exports by default all the administrative commands +# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve +# security of read only slaves using 'rename-command' to shadow all the +# administrative / dangerous commands. +slave-read-only yes + +# Replication SYNC strategy: disk or socket. +# +# ------------------------------------------------------- +# WARNING: DISKLESS REPLICATION IS EXPERIMENTAL CURRENTLY +# ------------------------------------------------------- +# +# New slaves and reconnecting slaves that are not able to continue the replication +# process just receiving differences, need to do what is called a "full +# synchronization". An RDB file is transmitted from the master to the slaves. +# The transmission can happen in two different ways: +# +# 1) Disk-backed: The Redis master creates a new process that writes the RDB +# file on disk. Later the file is transferred by the parent +# process to the slaves incrementally. +# 2) Diskless: The Redis master creates a new process that directly writes the +# RDB file to slave sockets, without touching the disk at all. +# +# With disk-backed replication, while the RDB file is generated, more slaves +# can be queued and served with the RDB file as soon as the current child producing +# the RDB file finishes its work. With diskless replication instead once +# the transfer starts, new slaves arriving will be queued and a new transfer +# will start when the current one terminates. +# +# When diskless replication is used, the master waits a configurable amount of +# time (in seconds) before starting the transfer in the hope that multiple slaves +# will arrive and the transfer can be parallelized. +# +# With slow disks and fast (large bandwidth) networks, diskless replication +# works better. +repl-diskless-sync no + +# When diskless replication is enabled, it is possible to configure the delay +# the server waits in order to spawn the child that transfers the RDB via socket +# to the slaves. +# +# This is important since once the transfer starts, it is not possible to serve +# new slaves arriving, that will be queued for the next RDB transfer, so the server +# waits a delay in order to let more slaves arrive. +# +# The delay is specified in seconds, and by default is 5 seconds. To disable +# it entirely just set it to 0 seconds and the transfer will start ASAP. +repl-diskless-sync-delay 5 + +# Slaves send PINGs to server in a predefined interval. It's possible to change +# this interval with the repl_ping_slave_period option. The default value is 10 +# seconds. +# +# repl-ping-slave-period 10 + +# The following option sets the replication timeout for: +# +# 1) Bulk transfer I/O during SYNC, from the point of view of slave. +# 2) Master timeout from the point of view of slaves (data, pings). +# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings). +# +# It is important to make sure that this value is greater than the value +# specified for repl-ping-slave-period otherwise a timeout will be detected +# every time there is low traffic between the master and the slave. +# +# repl-timeout 60 + +# Disable TCP_NODELAY on the slave socket after SYNC? +# +# If you select "yes" Redis will use a smaller number of TCP packets and +# less bandwidth to send data to slaves. But this can add a delay for +# the data to appear on the slave side, up to 40 milliseconds with +# Linux kernels using a default configuration. +# +# If you select "no" the delay for data to appear on the slave side will +# be reduced but more bandwidth will be used for replication. +# +# By default we optimize for low latency, but in very high traffic conditions +# or when the master and slaves are many hops away, turning this to "yes" may +# be a good idea. +repl-disable-tcp-nodelay no + +# Set the replication backlog size. The backlog is a buffer that accumulates +# slave data when slaves are disconnected for some time, so that when a slave +# wants to reconnect again, often a full resync is not needed, but a partial +# resync is enough, just passing the portion of data the slave missed while +# disconnected. +# +# The bigger the replication backlog, the longer the time the slave can be +# disconnected and later be able to perform a partial resynchronization. +# +# The backlog is only allocated once there is at least a slave connected. +# +# repl-backlog-size 1mb + +# After a master has no longer connected slaves for some time, the backlog +# will be freed. The following option configures the amount of seconds that +# need to elapse, starting from the time the last slave disconnected, for +# the backlog buffer to be freed. +# +# A value of 0 means to never release the backlog. +# +# repl-backlog-ttl 3600 + +# The slave priority is an integer number published by Redis in the INFO output. +# It is used by Redis Sentinel in order to select a slave to promote into a +# master if the master is no longer working correctly. +# +# A slave with a low priority number is considered better for promotion, so +# for instance if there are three slaves with priority 10, 100, 25 Sentinel will +# pick the one with priority 10, that is the lowest. +# +# However a special priority of 0 marks the slave as not able to perform the +# role of master, so a slave with priority of 0 will never be selected by +# Redis Sentinel for promotion. +# +# By default the priority is 100. +slave-priority 100 + +# It is possible for a master to stop accepting writes if there are less than +# N slaves connected, having a lag less or equal than M seconds. +# +# The N slaves need to be in "online" state. +# +# The lag in seconds, that must be <= the specified value, is calculated from +# the last ping received from the slave, that is usually sent every second. +# +# This option does not GUARANTEE that N replicas will accept the write, but +# will limit the window of exposure for lost writes in case not enough slaves +# are available, to the specified number of seconds. +# +# For example to require at least 3 slaves with a lag <= 10 seconds use: +# +# min-slaves-to-write 3 +# min-slaves-max-lag 10 +# +# Setting one or the other to 0 disables the feature. +# +# By default min-slaves-to-write is set to 0 (feature disabled) and +# min-slaves-max-lag is set to 10. + +# A Redis master is able to list the address and port of the attached +# slaves in different ways. For example the "INFO replication" section +# offers this information, which is used, among other tools, by +# Redis Sentinel in order to discover slave instances. +# Another place where this info is available is in the output of the +# "ROLE" command of a masteer. +# +# The listed IP and address normally reported by a slave is obtained +# in the following way: +# +# IP: The address is auto detected by checking the peer address +# of the socket used by the slave to connect with the master. +# +# Port: The port is communicated by the slave during the replication +# handshake, and is normally the port that the slave is using to +# list for connections. +# +# However when port forwarding or Network Address Translation (NAT) is +# used, the slave may be actually reachable via different IP and port +# pairs. The following two options can be used by a slave in order to +# report to its master a specific set of IP and port, so that both INFO +# and ROLE will report those values. +# +# There is no need to use both the options if you need to override just +# the port or the IP address. +# +# slave-announce-ip 5.5.5.5 +# slave-announce-port 1234 + +################################## SECURITY ################################### + +# Require clients to issue AUTH before processing any other +# commands. This might be useful in environments in which you do not trust +# others with access to the host running redis-server. +# +# This should stay commented out for backward compatibility and because most +# people do not need auth (e.g. they run their own servers). +# +# Warning: since Redis is pretty fast an outside user can try up to +# 150k passwords per second against a good box. This means that you should +# use a very strong password otherwise it will be very easy to break. +# +# requirepass foobared + +# Command renaming. +# +# It is possible to change the name of dangerous commands in a shared +# environment. For instance the CONFIG command may be renamed into something +# hard to guess so that it will still be available for internal-use tools +# but not available for general clients. +# +# Example: +# +# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 +# +# It is also possible to completely kill a command by renaming it into +# an empty string: +# +# rename-command CONFIG "" +# +# Please note that changing the name of commands that are logged into the +# AOF file or transmitted to slaves may cause problems. + +################################### LIMITS #################################### + +# Set the max number of connected clients at the same time. By default +# this limit is set to 10000 clients, however if the Redis server is not +# able to configure the process file limit to allow for the specified limit +# the max number of allowed clients is set to the current file limit +# minus 32 (as Redis reserves a few file descriptors for internal uses). +# +# Once the limit is reached Redis will close all the new connections sending +# an error 'max number of clients reached'. +# +# maxclients 10000 +maxclients 512 + +# Don't use more memory than the specified amount of bytes. +# When the memory limit is reached Redis will try to remove keys +# according to the eviction policy selected (see maxmemory-policy). +# +# If Redis can't remove keys according to the policy, or if the policy is +# set to 'noeviction', Redis will start to reply with errors to commands +# that would use more memory, like SET, LPUSH, and so on, and will continue +# to reply to read-only commands like GET. +# +# This option is usually useful when using Redis as an LRU cache, or to set +# a hard memory limit for an instance (using the 'noeviction' policy). +# +# WARNING: If you have slaves attached to an instance with maxmemory on, +# the size of the output buffers needed to feed the slaves are subtracted +# from the used memory count, so that network problems / resyncs will +# not trigger a loop where keys are evicted, and in turn the output +# buffer of slaves is full with DELs of keys evicted triggering the deletion +# of more keys, and so forth until the database is completely emptied. +# +# In short... if you have slaves attached it is suggested that you set a lower +# limit for maxmemory so that there is some free RAM on the system for slave +# output buffers (but this is not needed if the policy is 'noeviction'). +# +# maxmemory + +# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory +# is reached. You can select among five behaviors: +# +# volatile-lru -> remove the key with an expire set using an LRU algorithm +# allkeys-lru -> remove any key according to the LRU algorithm +# volatile-random -> remove a random key with an expire set +# allkeys-random -> remove a random key, any key +# volatile-ttl -> remove the key with the nearest expire time (minor TTL) +# noeviction -> don't expire at all, just return an error on write operations +# +# Note: with any of the above policies, Redis will return an error on write +# operations, when there are no suitable keys for eviction. +# +# At the date of writing these commands are: set setnx setex append +# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd +# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby +# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby +# getset mset msetnx exec sort +# +# The default is: +# +# maxmemory-policy noeviction + +# LRU and minimal TTL algorithms are not precise algorithms but approximated +# algorithms (in order to save memory), so you can tune it for speed or +# accuracy. For default Redis will check five keys and pick the one that was +# used less recently, you can change the sample size using the following +# configuration directive. +# +# The default of 5 produces good enough results. 10 Approximates very closely +# true LRU but costs a bit more CPU. 3 is very fast but not very accurate. +# +# maxmemory-samples 5 + +############################## APPEND ONLY MODE ############################### + +# By default Redis asynchronously dumps the dataset on disk. This mode is +# good enough in many applications, but an issue with the Redis process or +# a power outage may result into a few minutes of writes lost (depending on +# the configured save points). +# +# The Append Only File is an alternative persistence mode that provides +# much better durability. For instance using the default data fsync policy +# (see later in the config file) Redis can lose just one second of writes in a +# dramatic event like a server power outage, or a single write if something +# wrong with the Redis process itself happens, but the operating system is +# still running correctly. +# +# AOF and RDB persistence can be enabled at the same time without problems. +# If the AOF is enabled on startup Redis will load the AOF, that is the file +# with the better durability guarantees. +# +# Please check http://redis.io/topics/persistence for more information. + +appendonly no + +# The name of the append only file (default: "appendonly.aof") + +appendfilename "appendonly.aof" + +# The fsync() call tells the Operating System to actually write data on disk +# instead of waiting for more data in the output buffer. Some OS will really flush +# data on disk, some other OS will just try to do it ASAP. +# +# Redis supports three different modes: +# +# no: don't fsync, just let the OS flush the data when it wants. Faster. +# always: fsync after every write to the append only log. Slow, Safest. +# everysec: fsync only one time every second. Compromise. +# +# The default is "everysec", as that's usually the right compromise between +# speed and data safety. It's up to you to understand if you can relax this to +# "no" that will let the operating system flush the output buffer when +# it wants, for better performances (but if you can live with the idea of +# some data loss consider the default persistence mode that's snapshotting), +# or on the contrary, use "always" that's very slow but a bit safer than +# everysec. +# +# More details please check the following article: +# http://antirez.com/post/redis-persistence-demystified.html +# +# If unsure, use "everysec". + +# appendfsync always +appendfsync everysec +# appendfsync no + +# When the AOF fsync policy is set to always or everysec, and a background +# saving process (a background save or AOF log background rewriting) is +# performing a lot of I/O against the disk, in some Linux configurations +# Redis may block too long on the fsync() call. Note that there is no fix for +# this currently, as even performing fsync in a different thread will block +# our synchronous write(2) call. +# +# In order to mitigate this problem it's possible to use the following option +# that will prevent fsync() from being called in the main process while a +# BGSAVE or BGREWRITEAOF is in progress. +# +# This means that while another child is saving, the durability of Redis is +# the same as "appendfsync none". In practical terms, this means that it is +# possible to lose up to 30 seconds of log in the worst scenario (with the +# default Linux settings). +# +# If you have latency problems turn this to "yes". Otherwise leave it as +# "no" that is the safest pick from the point of view of durability. + +no-appendfsync-on-rewrite no + +# Automatic rewrite of the append only file. +# Redis is able to automatically rewrite the log file implicitly calling +# BGREWRITEAOF when the AOF log size grows by the specified percentage. +# +# This is how it works: Redis remembers the size of the AOF file after the +# latest rewrite (if no rewrite has happened since the restart, the size of +# the AOF at startup is used). +# +# This base size is compared to the current size. If the current size is +# bigger than the specified percentage, the rewrite is triggered. Also +# you need to specify a minimal size for the AOF file to be rewritten, this +# is useful to avoid rewriting the AOF file even if the percentage increase +# is reached but it is still pretty small. +# +# Specify a percentage of zero in order to disable the automatic AOF +# rewrite feature. + +auto-aof-rewrite-percentage 100 +auto-aof-rewrite-min-size 64mb + +# An AOF file may be found to be truncated at the end during the Redis +# startup process, when the AOF data gets loaded back into memory. +# This may happen when the system where Redis is running +# crashes, especially when an ext4 filesystem is mounted without the +# data=ordered option (however this can't happen when Redis itself +# crashes or aborts but the operating system still works correctly). +# +# Redis can either exit with an error when this happens, or load as much +# data as possible (the default now) and start if the AOF file is found +# to be truncated at the end. The following option controls this behavior. +# +# If aof-load-truncated is set to yes, a truncated AOF file is loaded and +# the Redis server starts emitting a log to inform the user of the event. +# Otherwise if the option is set to no, the server aborts with an error +# and refuses to start. When the option is set to no, the user requires +# to fix the AOF file using the "redis-check-aof" utility before to restart +# the server. +# +# Note that if the AOF file will be found to be corrupted in the middle +# the server will still exit with an error. This option only applies when +# Redis will try to read more data from the AOF file but not enough bytes +# will be found. +aof-load-truncated yes + +################################ LUA SCRIPTING ############################### + +# Max execution time of a Lua script in milliseconds. +# +# If the maximum execution time is reached Redis will log that a script is +# still in execution after the maximum allowed time and will start to +# reply to queries with an error. +# +# When a long running script exceeds the maximum execution time only the +# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be +# used to stop a script that did not yet called write commands. The second +# is the only way to shut down the server in the case a write command was +# already issued by the script but the user doesn't want to wait for the natural +# termination of the script. +# +# Set it to 0 or a negative value for unlimited execution without warnings. +lua-time-limit 5000 + +################################ REDIS CLUSTER ############################### +# +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however +# in order to mark it as "mature" we need to wait for a non trivial percentage +# of users to deploy it in production. +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# Normal Redis instances can't be part of a Redis Cluster; only nodes that are +# started as cluster nodes can. In order to start a Redis instance as a +# cluster node enable the cluster support uncommenting the following: +# +# cluster-enabled yes + +# Every cluster node has a cluster configuration file. This file is not +# intended to be edited by hand. It is created and updated by Redis nodes. +# Every Redis Cluster node requires a different cluster configuration file. +# Make sure that instances running in the same system do not have +# overlapping cluster configuration file names. +# +# cluster-config-file nodes-6379.conf + +# Cluster node timeout is the amount of milliseconds a node must be unreachable +# for it to be considered in failure state. +# Most other internal time limits are multiple of the node timeout. +# +# cluster-node-timeout 15000 + +# A slave of a failing master will avoid to start a failover if its data +# looks too old. +# +# There is no simple way for a slave to actually have a exact measure of +# its "data age", so the following two checks are performed: +# +# 1) If there are multiple slaves able to failover, they exchange messages +# in order to try to give an advantage to the slave with the best +# replication offset (more data from the master processed). +# Slaves will try to get their rank by offset, and apply to the start +# of the failover a delay proportional to their rank. +# +# 2) Every single slave computes the time of the last interaction with +# its master. This can be the last ping or command received (if the master +# is still in the "connected" state), or the time that elapsed since the +# disconnection with the master (if the replication link is currently down). +# If the last interaction is too old, the slave will not try to failover +# at all. +# +# The point "2" can be tuned by user. Specifically a slave will not perform +# the failover if, since the last interaction with the master, the time +# elapsed is greater than: +# +# (node-timeout * slave-validity-factor) + repl-ping-slave-period +# +# So for example if node-timeout is 30 seconds, and the slave-validity-factor +# is 10, and assuming a default repl-ping-slave-period of 10 seconds, the +# slave will not try to failover if it was not able to talk with the master +# for longer than 310 seconds. +# +# A large slave-validity-factor may allow slaves with too old data to failover +# a master, while a too small value may prevent the cluster from being able to +# elect a slave at all. +# +# For maximum availability, it is possible to set the slave-validity-factor +# to a value of 0, which means, that slaves will always try to failover the +# master regardless of the last time they interacted with the master. +# (However they'll always try to apply a delay proportional to their +# offset rank). +# +# Zero is the only value able to guarantee that when all the partitions heal +# the cluster will always be able to continue. +# +# cluster-slave-validity-factor 10 + +# Cluster slaves are able to migrate to orphaned masters, that are masters +# that are left without working slaves. This improves the cluster ability +# to resist to failures as otherwise an orphaned master can't be failed over +# in case of failure if it has no working slaves. +# +# Slaves migrate to orphaned masters only if there are still at least a +# given number of other working slaves for their old master. This number +# is the "migration barrier". A migration barrier of 1 means that a slave +# will migrate only if there is at least 1 other working slave for its master +# and so forth. It usually reflects the number of slaves you want for every +# master in your cluster. +# +# Default is 1 (slaves migrate only if their masters remain with at least +# one slave). To disable migration just set it to a very large value. +# A value of 0 can be set but is useful only for debugging and dangerous +# in production. +# +# cluster-migration-barrier 1 + +# By default Redis Cluster nodes stop accepting queries if they detect there +# is at least an hash slot uncovered (no available node is serving it). +# This way if the cluster is partially down (for example a range of hash slots +# are no longer covered) all the cluster becomes, eventually, unavailable. +# It automatically returns available as soon as all the slots are covered again. +# +# However sometimes you want the subset of the cluster which is working, +# to continue to accept queries for the part of the key space that is still +# covered. In order to do so, just set the cluster-require-full-coverage +# option to no. +# +# cluster-require-full-coverage yes + +# In order to setup your cluster make sure to read the documentation +# available at http://redis.io web site. + +################################## SLOW LOG ################################### + +# The Redis Slow Log is a system to log queries that exceeded a specified +# execution time. The execution time does not include the I/O operations +# like talking with the client, sending the reply and so forth, +# but just the time needed to actually execute the command (this is the only +# stage of command execution where the thread is blocked and can not serve +# other requests in the meantime). +# +# You can configure the slow log with two parameters: one tells Redis +# what is the execution time, in microseconds, to exceed in order for the +# command to get logged, and the other parameter is the length of the +# slow log. When a new command is logged the oldest one is removed from the +# queue of logged commands. + +# The following time is expressed in microseconds, so 1000000 is equivalent +# to one second. Note that a negative number disables the slow log, while +# a value of zero forces the logging of every command. +slowlog-log-slower-than 10000 + +# There is no limit to this length. Just be aware that it will consume memory. +# You can reclaim memory used by the slow log with SLOWLOG RESET. +slowlog-max-len 128 + +################################ LATENCY MONITOR ############################## + +# The Redis latency monitoring subsystem samples different operations +# at runtime in order to collect data related to possible sources of +# latency of a Redis instance. +# +# Via the LATENCY command this information is available to the user that can +# print graphs and obtain reports. +# +# The system only logs operations that were performed in a time equal or +# greater than the amount of milliseconds specified via the +# latency-monitor-threshold configuration directive. When its value is set +# to zero, the latency monitor is turned off. +# +# By default latency monitoring is disabled since it is mostly not needed +# if you don't have latency issues, and collecting data has a performance +# impact, that while very small, can be measured under big load. Latency +# monitoring can easily be enabled at runtime using the command +# "CONFIG SET latency-monitor-threshold " if needed. +latency-monitor-threshold 0 + +############################# EVENT NOTIFICATION ############################## + +# Redis can notify Pub/Sub clients about events happening in the key space. +# This feature is documented at http://redis.io/topics/notifications +# +# For instance if keyspace events notification is enabled, and a client +# performs a DEL operation on key "foo" stored in the Database 0, two +# messages will be published via Pub/Sub: +# +# PUBLISH __keyspace@0__:foo del +# PUBLISH __keyevent@0__:del foo +# +# It is possible to select the events that Redis will notify among a set +# of classes. Every class is identified by a single character: +# +# K Keyspace events, published with __keyspace@__ prefix. +# E Keyevent events, published with __keyevent@__ prefix. +# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... +# $ String commands +# l List commands +# s Set commands +# h Hash commands +# z Sorted set commands +# x Expired events (events generated every time a key expires) +# e Evicted events (events generated when a key is evicted for maxmemory) +# A Alias for g$lshzxe, so that the "AKE" string means all the events. +# +# The "notify-keyspace-events" takes as argument a string that is composed +# of zero or multiple characters. The empty string means that notifications +# are disabled. +# +# Example: to enable list and generic events, from the point of view of the +# event name, use: +# +# notify-keyspace-events Elg +# +# Example 2: to get the stream of the expired keys subscribing to channel +# name __keyevent@0__:expired use: +# +# notify-keyspace-events Ex +# +# By default all notifications are disabled because most users don't need +# this feature and the feature has some overhead. Note that if you don't +# specify at least one of K or E, no events will be delivered. +notify-keyspace-events "" + +############################### ADVANCED CONFIG ############################### + +# Hashes are encoded using a memory efficient data structure when they have a +# small number of entries, and the biggest entry does not exceed a given +# threshold. These thresholds can be configured using the following directives. +hash-max-ziplist-entries 512 +hash-max-ziplist-value 64 + +# Lists are also encoded in a special way to save a lot of space. +# The number of entries allowed per internal list node can be specified +# as a fixed maximum size or a maximum number of elements. +# For a fixed maximum size, use -5 through -1, meaning: +# -5: max size: 64 Kb <-- not recommended for normal workloads +# -4: max size: 32 Kb <-- not recommended +# -3: max size: 16 Kb <-- probably not recommended +# -2: max size: 8 Kb <-- good +# -1: max size: 4 Kb <-- good +# Positive numbers mean store up to _exactly_ that number of elements +# per list node. +# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), +# but if your use case is unique, adjust the settings as necessary. +list-max-ziplist-size -2 + +# Lists may also be compressed. +# Compress depth is the number of quicklist ziplist nodes from *each* side of +# the list to *exclude* from compression. The head and tail of the list +# are always uncompressed for fast push/pop operations. Settings are: +# 0: disable all list compression +# 1: depth 1 means "don't start compressing until after 1 node into the list, +# going from either the head or tail" +# So: [head]->node->node->...->node->[tail] +# [head], [tail] will always be uncompressed; inner nodes will compress. +# 2: [head]->[next]->node->node->...->node->[prev]->[tail] +# 2 here means: don't compress head or head->next or tail->prev or tail, +# but compress all nodes between them. +# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] +# etc. +list-compress-depth 0 + +# Sets have a special encoding in just one case: when a set is composed +# of just strings that happen to be integers in radix 10 in the range +# of 64 bit signed integers. +# The following configuration setting sets the limit in the size of the +# set in order to use this special memory saving encoding. +set-max-intset-entries 512 + +# Similarly to hashes and lists, sorted sets are also specially encoded in +# order to save a lot of space. This encoding is only used when the length and +# elements of a sorted set are below the following limits: +zset-max-ziplist-entries 128 +zset-max-ziplist-value 64 + +# HyperLogLog sparse representation bytes limit. The limit includes the +# 16 bytes header. When an HyperLogLog using the sparse representation crosses +# this limit, it is converted into the dense representation. +# +# A value greater than 16000 is totally useless, since at that point the +# dense representation is more memory efficient. +# +# The suggested value is ~ 3000 in order to have the benefits of +# the space efficient encoding without slowing down too much PFADD, +# which is O(N) with the sparse encoding. The value can be raised to +# ~ 10000 when CPU is not a concern, but space is, and the data set is +# composed of many HyperLogLogs with cardinality in the 0 - 15000 range. +hll-sparse-max-bytes 3000 + +# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in +# order to help rehashing the main Redis hash table (the one mapping top-level +# keys to values). The hash table implementation Redis uses (see dict.c) +# performs a lazy rehashing: the more operation you run into a hash table +# that is rehashing, the more rehashing "steps" are performed, so if the +# server is idle the rehashing is never complete and some more memory is used +# by the hash table. +# +# The default is to use this millisecond 10 times every second in order to +# actively rehash the main dictionaries, freeing memory when possible. +# +# If unsure: +# use "activerehashing no" if you have hard latency requirements and it is +# not a good thing in your environment that Redis can reply from time to time +# to queries with 2 milliseconds delay. +# +# use "activerehashing yes" if you don't have such hard requirements but +# want to free memory asap when possible. +activerehashing yes + +# The client output buffer limits can be used to force disconnection of clients +# that are not reading data from the server fast enough for some reason (a +# common reason is that a Pub/Sub client can't consume messages as fast as the +# publisher can produce them). +# +# The limit can be set differently for the three different classes of clients: +# +# normal -> normal clients including MONITOR clients +# slave -> slave clients +# pubsub -> clients subscribed to at least one pubsub channel or pattern +# +# The syntax of every client-output-buffer-limit directive is the following: +# +# client-output-buffer-limit +# +# A client is immediately disconnected once the hard limit is reached, or if +# the soft limit is reached and remains reached for the specified number of +# seconds (continuously). +# So for instance if the hard limit is 32 megabytes and the soft limit is +# 16 megabytes / 10 seconds, the client will get disconnected immediately +# if the size of the output buffers reach 32 megabytes, but will also get +# disconnected if the client reaches 16 megabytes and continuously overcomes +# the limit for 10 seconds. +# +# By default normal clients are not limited because they don't receive data +# without asking (in a push way), but just after a request, so only +# asynchronous clients may create a scenario where data is requested faster +# than it can read. +# +# Instead there is a default limit for pubsub and slave clients, since +# subscribers and slaves receive data in a push fashion. +# +# Both the hard or the soft limit can be disabled by setting them to zero. +client-output-buffer-limit normal 0 0 0 +client-output-buffer-limit slave 256mb 64mb 60 +client-output-buffer-limit pubsub 32mb 8mb 60 + +# Redis calls an internal function to perform many background tasks, like +# closing connections of clients in timeout, purging expired keys that are +# never requested, and so forth. +# +# Not all tasks are performed with the same frequency, but Redis checks for +# tasks to perform according to the specified "hz" value. +# +# By default "hz" is set to 10. Raising the value will use more CPU when +# Redis is idle, but at the same time will make Redis more responsive when +# there are many keys expiring at the same time, and timeouts may be +# handled with more precision. +# +# The range is between 1 and 500, however a value over 100 is usually not +# a good idea. Most users should use the default of 10 and raise this up to +# 100 only in environments where very low latency is required. +hz 10 + +# When a child rewrites the AOF file, if the following option is enabled +# the file will be fsync-ed every 32 MB of data generated. This is useful +# in order to commit the file to the disk more incrementally and avoid +# big latency spikes. +aof-rewrite-incremental-fsync yes diff --git a/roles/redis/vars/main.yml b/roles/redis/vars/main.yml new file mode 100644 index 0000000..3ea0165 --- /dev/null +++ b/roles/redis/vars/main.yml @@ -0,0 +1,4 @@ +--- + +redis_unixsocket: "/var/run/redis/redis.sock" +redis_unixsocketperm: 770 diff --git a/roles/systemd_exporter/defaults/main.yml b/roles/systemd_exporter/defaults/main.yml new file mode 100644 index 0000000..b23eb4c --- /dev/null +++ b/roles/systemd_exporter/defaults/main.yml @@ -0,0 +1,2 @@ +--- +systemd_exporter_include: '^rclone.*\.service' diff --git a/roles/systemd_exporter/handlers/main.yml b/roles/systemd_exporter/handlers/main.yml new file mode 100644 index 0000000..c25aafd --- /dev/null +++ b/roles/systemd_exporter/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: restart systemd_exporter + systemd: + daemon_reload: true + enabled: true + name: systemd_exporter + state: restarted diff --git a/roles/systemd_exporter/tasks/main.yml b/roles/systemd_exporter/tasks/main.yml new file mode 100644 index 0000000..cd5e3aa --- /dev/null +++ b/roles/systemd_exporter/tasks/main.yml @@ -0,0 +1,52 @@ +--- + +- name: Get latest systemd_exporter version + github_release: + user: povilasv + repo: systemd_exporter + action: latest_release + token: "{{ vault_github_token }}" + delegate_to: localhost + run_once: true + register: systemd_exporter_version +- name: "{{ systemd_exporter_version }}" + set_fact: + systemd_exporter_version: "{{ systemd_exporter_version | replace ('v', '', 1) | trim }}" + run_once: true + +- name: download systemd_exporter {{ systemd_exporter_version.tag }} from GitHub + get_url: + url: "https://github.com/povilasv/systemd_exporter/releases/download/\ + v{{ systemd_exporter_version.tag }}/systemd_exporter-{{ systemd_exporter_version.tag }}\ + .linux-{{ deb_architecture }}.tar.gz" + dest: "/tmp/systemd_exporter-{{ systemd_exporter_version.tag }}-linux-{{ deb_architecture }}.tar.gz" + register: _download_archive + until: _download_archive is succeeded + retries: 3 + delay: 5 + +- name: unpack systemd_exporter binaries + unarchive: + src: "/tmp/systemd_exporter-{{ systemd_exporter_version.tag }}-linux-{{ deb_architecture }}.tar.gz" + dest: "/tmp" + creates: "/tmp/systemd_exporter-{{ systemd_exporter_version.tag }}.linux-{{ deb_architecture }}" + remote_src: true + +- name: Copy systemd_exporter + copy: + src: "/tmp/systemd_exporter-{{ systemd_exporter_version.tag }}.linux-{{ deb_architecture }}/systemd_exporter" + dest: "{{ systemd_exporter_install_dir }}/systemd_exporter" + remote_src: true + owner: "{{ systemd_exporter_system_user }}" + group: "{{ systemd_exporter_system_group }}" + mode: 0755 + notify: restart systemd_exporter + +- name: Copy the systemd_exporter systemd service file + template: + src: systemd_exporter.service.j2 + dest: /etc/systemd/system/systemd_exporter.service + owner: root + group: root + mode: 0644 + notify: restart systemd_exporter diff --git a/roles/systemd_exporter/templates/systemd_exporter.service.j2 b/roles/systemd_exporter/templates/systemd_exporter.service.j2 new file mode 100644 index 0000000..176d78b --- /dev/null +++ b/roles/systemd_exporter/templates/systemd_exporter.service.j2 @@ -0,0 +1,16 @@ +## Managed by Ansible ## + +[Unit] +Description=Prometheus Systemd Exporter +After=network-online.target + +[Service] +Type=simple +User={{ systemd_exporter_system_user }} +Group={{ systemd_exporter_system_group }} +ExecStart={{ systemd_exporter_install_dir }}/systemd_exporter --systemd.collector.unit-include="{{ systemd_exporter_include }}" +Restart=always +RestartSec=1 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/systemd_exporter/vars/main.yml b/roles/systemd_exporter/vars/main.yml new file mode 100644 index 0000000..19595de --- /dev/null +++ b/roles/systemd_exporter/vars/main.yml @@ -0,0 +1,5 @@ +--- +# Variables +systemd_exporter_install_dir: "/usr/local/bin" +systemd_exporter_system_group: "node-exporter" +systemd_exporter_system_user: "{{ systemd_exporter_system_group }}" diff --git a/roles/webserver/handlers/main.yml b/roles/webserver/handlers/main.yml new file mode 100644 index 0000000..7bbfd09 --- /dev/null +++ b/roles/webserver/handlers/main.yml @@ -0,0 +1,11 @@ +--- +- name: reload nginx + systemd: + name: nginx.service + state: reloaded + +- name: restart nginx + systemd: + name: nginx.service + daemon_reload: true + state: restarted diff --git a/roles/webserver/meta/main.yml b/roles/webserver/meta/main.yml new file mode 100644 index 0000000..9a05f4a --- /dev/null +++ b/roles/webserver/meta/main.yml @@ -0,0 +1,8 @@ +--- +dependencies: + - role: rclone + - role: nginx +# - role: nginx_exporter + - role: php +# - role: php_fpm_exporter + - role: redis diff --git a/roles/webserver/tasks/main.yml b/roles/webserver/tasks/main.yml new file mode 100644 index 0000000..1b0dfdc --- /dev/null +++ b/roles/webserver/tasks/main.yml @@ -0,0 +1,15 @@ +--- +- name: Mount Volume + import_tasks: volume.yml + +- name: Configure Rclone + import_tasks: rclone.yml + +- name: Configure Nginx + import_tasks: nginx.yml + +- name: Configure PHP + import_tasks: php.yml + +- name: Flush handlers befor continue + meta: flush_handlers diff --git a/roles/webserver/tasks/nginx.yml b/roles/webserver/tasks/nginx.yml new file mode 100644 index 0000000..eefe248 --- /dev/null +++ b/roles/webserver/tasks/nginx.yml @@ -0,0 +1,55 @@ +--- + +- name: Copy Nginx configs + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: 0644 + loop: + - {src: "nginx.conf.j2", dest: "/etc/nginx/nginx.conf"} + - {src: "cert.conf.j2", dest: "/etc/nginx/global/cert.conf"} + - {src: "header.conf.j2", dest: "/etc/nginx/global/header.conf"} + - {src: "proxy.conf.j2", dest: "/etc/nginx/global/proxy.conf"} + - {src: "php_optimization.j2", dest: "/etc/nginx/global/php_optimization"} + notify: reload nginx + +- name: Copy virtual server configs + template: + src: "{{ item }}" + dest: /etc/nginx/conf.d/{{ item | basename | regex_replace('\.j2$', '') }} + mode: 0644 + with_fileglob: "../templates/conf.d/*.j2" + notify: reload nginx + +## Certificates + +- name: Create Certificate directory + file: + path: "{{ webserver_nginx_cert_path }}" + state: directory + mode: 0755 + +- name: Copy SSL certificates for {{ webserver_domain }} + copy: + remote_src: true + # make sure that ssl certs are available + src: "{{ lego_config_dir }}/certificates/{{ webserver_domain }}.{{ item }}" + dest: "{{ webserver_nginx_cert_path }}/{{ webserver_domain }}.{{ item }}" + owner: root + group: root + mode: 0600 + loop: [crt, key, issuer.crt] + notify: reload nginx + +- name: Create nginx.service.d directory + file: + path: /etc/systemd/system/nginx.service.d + mode: 0755 + state: directory + +- name: Increase max open files + template: + src: nginx_systemd.conf.j2 + dest: /etc/systemd/system/nginx.service.d/nginx.conf + mode: 0644 + notify: restart nginx diff --git a/roles/webserver/tasks/php.yml b/roles/webserver/tasks/php.yml new file mode 100644 index 0000000..b1c8ca4 --- /dev/null +++ b/roles/webserver/tasks/php.yml @@ -0,0 +1,37 @@ +--- + +- name: Set PHP options for FPM + ini_file: + path: /etc/php/{{ php_version }}/fpm/php.ini + section: "{{ item.section | default('PHP') }}" + option: "{{ item.option }}" + value: "{{ item.value }}" + state: "{{ item.state | default('present') }}" + loop: "{{ php_fpm_ini_options }}" + when: '"fpm" in php_modules' + notify: restart php-fpm + +- name: Configure FPM pool + lineinfile: + path: /etc/php/{{ php_version }}/fpm/pool.d/www.conf + regexp: '^{{ item.option }}\s' + line: '{{ item.option }} = {{ item.value }}' + loop: "{{ php_fpm_pool_options }}" + when: '"fpm" in php_modules' + notify: restart php-fpm + +- name: Configure FPM environment variables + replace: + path: /etc/php/{{ php_version }}/fpm/pool.d/www.conf + regexp: "^{{ item.regexp }}" + replace: "{{ item.replace }}" + loop: + - {regexp: ";env", replace: "env"} + - {regexp: ";clear_env", replace: "clear_env"} + when: '"fpm" in php_modules' + notify: restart php-fpm + +- name: Install imagemagick package + apt: + name: imagemagick + when: '"imagick" in php_modules' diff --git a/roles/webserver/tasks/rclone.yml b/roles/webserver/tasks/rclone.yml new file mode 100644 index 0000000..b13b24d --- /dev/null +++ b/roles/webserver/tasks/rclone.yml @@ -0,0 +1,8 @@ +--- +- name: Copy rclone config file + template: + src: "rclone.conf.j2" + dest: "{{ rclone_config_file }}" + mode: 0600 + # rclone config file changes while using to force update via ansible use rclone_config_force + force: "{{ rclone_config_force }}" diff --git a/roles/webserver/tasks/volume.yml b/roles/webserver/tasks/volume.yml new file mode 100644 index 0000000..71dea40 --- /dev/null +++ b/roles/webserver/tasks/volume.yml @@ -0,0 +1,22 @@ +--- + +- name: Gather hcloud volume infos + hetzner.hcloud.hcloud_volume_info: + api_token: "{{ vault_hcloud_token }}" + name: "{{ hcloud_webserver_volume_name }}" + delegate_to: localhost + register: web_hcloud_volume + +- name: Creates mount directory + file: + path: "{{ hcloud_webserver_volume_path }}" + state: directory + force: false + +- name: Mount hcloud volume + ansible.posix.mount: + path: "{{ hcloud_webserver_volume_path }}" + src: "{{ web_hcloud_volume.hcloud_volume_info[0].linux_device }}" + fstype: ext4 + opts: discard,nofail,defaults + state: mounted diff --git a/roles/webserver/templates/cert.conf.j2 b/roles/webserver/templates/cert.conf.j2 new file mode 100644 index 0000000..c6ae141 --- /dev/null +++ b/roles/webserver/templates/cert.conf.j2 @@ -0,0 +1,6 @@ +## Managed by Ansible ## + +# Certificates +ssl_certificate {{ webserver_nginx_cert_path }}/{{ webserver_domain }}.crt; +ssl_certificate_key {{ webserver_nginx_cert_path }}/{{ webserver_domain }}.key; +ssl_trusted_certificate {{ webserver_nginx_cert_path }}/{{ webserver_domain }}.issuer.crt; \ No newline at end of file diff --git a/roles/webserver/templates/conf.d/cloud.conf.j2 b/roles/webserver/templates/conf.d/cloud.conf.j2 new file mode 100644 index 0000000..eedc8bd --- /dev/null +++ b/roles/webserver/templates/conf.d/cloud.conf.j2 @@ -0,0 +1,182 @@ +## Managed by Ansible ## + +upstream nextcloud-notify-push { + server unix:{{ nextcloud_notify_push_socket }}; +} + +# Set the `immutable` cache control options only for assets with a cache busting `v` argument +map $arg_v $asset_immutable { + "" ""; + default "immutable"; +} + + +server { + listen 80; + listen [::]:80; + server_name {{ nextcloud_domain_name }} www.{{ nextcloud_domain_name }}; + # enforce https + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name {{ nextcloud_domain_name }} www.{{ nextcloud_domain_name }}; + include global/cert.conf; + + # Path to the root of your installation + root {{ nextcloud_dir }}; + + # HSTS settings + # WARNING: Only add the preload option once you read about + # the consequences in https://hstspreload.org/. This option + # will add the domain to a hardcoded list that is shipped + # in all major browsers and getting removed from this list + # could take several months. + add_header Strict-Transport-Security "max-age=63072000" always; + + # set max upload size and increase upload timeout: + client_max_body_size {{ nextcloud_max_upload_size }}; + client_body_timeout 300s; + fastcgi_buffers 64 4K; + + # Enable gzip but do not remove ETag headers + gzip on; + gzip_vary on; + gzip_comp_level 4; + gzip_min_length 256; + gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; + gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; + + # Pagespeed is not supported by Nextcloud, so if your server is built + # with the `ngx_pagespeed` module, uncomment this line to disable it. + #pagespeed off; + + # The settings allows you to optimize the HTTP2 bandwitdth. + # See https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements/ + # for tunning hints + client_body_buffer_size 512k; + + # HTTP response headers borrowed from Nextcloud `.htaccess` + add_header Referrer-Policy "no-referrer" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Download-Options "noopen" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Permitted-Cross-Domain-Policies "none" always; + add_header X-Robots-Tag "none" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Remove X-Powered-By, which is an information leak + fastcgi_hide_header X-Powered-By; + + # Specify how to handle directories -- specifying `/index.php$request_uri` + # here as the fallback means that Nginx always exhibits the desired behaviour + # when a client requests a path that corresponds to a directory that exists + # on the server. In particular, if that directory contains an index.php file, + # that file is correctly served; if it doesn't, then the request is passed to + # the front-end controller. This consistent behaviour means that we don't need + # to specify custom rules for certain paths (e.g. images and other assets, + # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus + # `try_files $uri $uri/ /index.php$request_uri` + # always provides the desired behaviour. + index index.php index.html /index.php$request_uri; + + # Rule borrowed from `.htaccess` to handle Microsoft DAV clients + location = / { + if ( $http_user_agent ~ ^DavClnt ) { + return 302 /remote.php/webdav/$is_args$args; + } + } + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + # Make a regex exception for `/.well-known` so that clients can still + # access it despite the existence of the regex rule + # `location ~ /(\.|autotest|...)` which would otherwise handle requests + # for `/.well-known`. + location ^~ /.well-known { + # The rules in this block are an adaptation of the rules + # in `.htaccess` that concern `/.well-known`. + + location = /.well-known/carddav { return 301 /remote.php/dav/; } + location = /.well-known/caldav { return 301 /remote.php/dav/; } + + location /.well-known/acme-challenge { try_files $uri $uri/ =404; } + location /.well-known/pki-validation { try_files $uri $uri/ =404; } + + # Let Nextcloud's API for `/.well-known` URIs handle all other + # requests by passing them to the front-end controller. + return 301 /index.php$request_uri; + } + + # Rules borrowed from `.htaccess` to hide certain paths from clients + location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; } + location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; } + + # Ensure this block, which passes PHP files to the PHP process, is above the blocks + # which handle static assets (as seen below). If this block is not declared first, + # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php` + # to the URI, resulting in a HTTP 500 error response. + location ~ \.php(?:$|/) { + # Required for legacy support + rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri; + + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + set $path_info $fastcgi_path_info; + + try_files $fastcgi_script_name =404; + + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $path_info; + fastcgi_param HTTPS on; + + fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice + fastcgi_param front_controller_active true; # Enable pretty urls + fastcgi_pass php-handler; + + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + + fastcgi_max_temp_file_size 0; + } + + location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite|map)$ { + try_files $uri /index.php$request_uri; + add_header Cache-Control "public, max-age=15778463, $asset_immutable"; + access_log off; # Optional: Don't log access to assets + + location ~ \.wasm$ { + default_type application/wasm; + } + } + + location ~ \.woff2?$ { + try_files $uri /index.php$request_uri; + expires 7d; # Cache-Control policy borrowed from `.htaccess` + access_log off; # Optional: Don't log access to assets + } + + # Rule borrowed from `.htaccess` + location /remote { + return 301 /remote.php$request_uri; + } + + location /push/ { + proxy_pass http://nextcloud-notify-push/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location / { + try_files $uri $uri/ /index.php$request_uri; + } +} diff --git a/roles/webserver/templates/conf.d/twirling.conf.j2 b/roles/webserver/templates/conf.d/twirling.conf.j2 new file mode 100644 index 0000000..3be6891 --- /dev/null +++ b/roles/webserver/templates/conf.d/twirling.conf.j2 @@ -0,0 +1,27 @@ +## Managed by Ansible ## + +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name {{ webserver_domain }} www.{{ webserver_domain }}; + # enforce https + return 301 https://$server_name$request_uri; +} + +server { + # Enable HTTP/2 + listen 443 ssl http2 default_server; + listen [::]:443 ssl http2 default_server; + server_name {{ webserver_domain }} www.{{ webserver_domain }}; + + include global/cert.conf; + include global/header.conf; + + add_header Strict-Transport-Security "max-age=63072000" always; + + # deny access and return teapot + location / { + deny all; + return 418; + } +} \ No newline at end of file diff --git a/roles/webserver/templates/header.conf.j2 b/roles/webserver/templates/header.conf.j2 new file mode 100644 index 0000000..0750e5d --- /dev/null +++ b/roles/webserver/templates/header.conf.j2 @@ -0,0 +1,57 @@ +## Managed by Ansible ## + +# Add headers to serve security related headers +# Before enabling Strict-Transport-Security headers please read into this +# topic first. +# add_header Strict-Transport-Security "max-age=15768000; +# includeSubDomains; preload;"; +# +# WARNING: Only add the preload option once you read about +# the consequences in https://hstspreload.org/. This option +# will add the domain to a hardcoded list that is shipped +# in all major browsers and getting removed from this list +# could take several months. +#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload"; +#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always; + +# config to don't allow the browser to render the page inside an frame or iframe +# and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking +# if you need to allow [i]frames, you can use SAMEORIGIN or even set an uri with ALLOW-FROM uri +# https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options +#add_header X-Frame-Options SAMEORIGIN; +add_header X-Frame-Options "SAMEORIGIN" always; + +# when serving user-supplied content, include a X-Content-Type-Options: nosniff header along with the Content-Type: header, +# to disable content-type sniffing on some browsers. +# https://www.owasp.org/index.php/List_of_useful_HTTP_headers +# currently suppoorted in IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx +# http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx +# 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020 +#add_header X-Content-Type-Options nosniff; +add_header X-Content-Type-Options "nosniff" always; + +# This header enables the Cross-site scripting (XSS) filter built into most recent web browsers. +# It's usually enabled by default anyway, so the role of this header is to re-enable the filter for +# this particular website if it was disabled by the user. +# https://www.owasp.org/index.php/List_of_useful_HTTP_headers +#add_header X-XSS-Protection "1; mode=block"; +add_header X-XSS-Protection "1; mode=block" always; + +# with Content Security Policy (CSP) enabled(and a browser that supports it(http://caniuse.com/#feat=contentsecuritypolicy), +# you can tell the browser that it can only download content from the domains you explicitly allow +# http://www.html5rocks.com/en/tutorials/security/content-security-policy/ +# https://www.owasp.org/index.php/Content_Security_Policy +# I need to change our application code so we can increase security by disabling 'unsafe-inline' 'unsafe-eval' +# directives for css and js(if you have inline css or js, you will need to keep it too). +# more: http://www.html5rocks.com/en/tutorials/security/content-security-policy/#inline-code-considered-harmful +#add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src to 'none'; frame-ancestors 'self' https://*.twirling.de https://twirling.de"; + +#add_header Referrer-Policy no-referrer; +add_header Referrer-Policy "no-referrer" always; + +add_header Feature-Policy "accelerometer 'none'; autoplay 'self'; geolocation 'self'; midi 'none'; notifications 'self'; push 'self'; sync-xhr 'self' https://*.twirling.de; microphone 'self'; camera 'self'; magnetometer 'none'; gyroscope 'none'; speaker 'self'; vibrate 'self'; fullscreen 'self'; payment 'none'; usb 'none'"; +add_header Permissions-Policy "geolocation=(self);midi=();notifications=(self);push=(self);sync-xhr=(self 'https://*.twirling.de');microphone=(self);camera=(self);magnetometer=();gyroscope=();speaker=(self);vibrate=();fullscreen=(self);payment=()"; + +# Add Alt-Svc header to negotiate HTTP/3. +#add_header Alt-Svc 'quic=":443"'; # Advertise that QUIC is available +#add_header QUIC-Status $quic; # Sent when QUIC was used \ No newline at end of file diff --git a/roles/webserver/templates/nginx.conf.j2 b/roles/webserver/templates/nginx.conf.j2 new file mode 100644 index 0000000..5ed2f63 --- /dev/null +++ b/roles/webserver/templates/nginx.conf.j2 @@ -0,0 +1,79 @@ +## Managed by Ansible ## + +user {{ webserver_user }}; +pid /var/run/nginx.pid; +error_log /var/log/nginx/error.log warn; + +# you must set worker processes based on your CPU cores, nginx does not benefit from setting more than that +worker_processes {{ webserver_nginx_worker_processes }}; + +# number of file descriptors used for nginx +# the limit for the maximum FDs on the server is usually set by the OS. +# if you don't set FD's then OS settings will be used which is by default 2000 +worker_rlimit_nofile {{ webserver_nginx_worker_rlimit_nofile }}; + +# only log critical errors +error_log /var/log/nginx/error.log crit; + +# provides the configuration file context in which the directives that affect connection processing are specified. +events { + # determines how much clients will be served per worker + # max clients = worker_connections * worker_processes + # max clients is also limited by the number of socket connections available on the system (~64k) + worker_connections 8192; + # optmized to serve many clients with each thread, essential for linux -- for testing environment + use epoll; + + # accept as many connections as possible, may flood worker connections if set too low -- for testing environment + multi_accept on; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '$request_time $upstream_response_time $ssl_protocol ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + aio threads; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + reset_timedout_connection on; + + # reduce the data that needs to be sent over network -- for testing environment + gzip on; + # gzip_static on; + gzip_min_length 10240; + gzip_comp_level 1; + gzip_vary on; + gzip_disable msie6; + gzip_proxied expired no-cache no-store private auth; + gzip_types + # text/html is always compressed by HttpGzipModule + text/css + text/javascript + text/xml + text/plain + text/x-component + application/javascript + application/x-javascript + application/json + application/xml + application/rss+xml + application/atom+xml + font/truetype + font/opentype + application/vnd.ms-fontobject + image/svg+xml; + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/global/*.conf; + + server_tokens off; +} \ No newline at end of file diff --git a/roles/webserver/templates/nginx_systemd.conf.j2 b/roles/webserver/templates/nginx_systemd.conf.j2 new file mode 100644 index 0000000..6095b3f --- /dev/null +++ b/roles/webserver/templates/nginx_systemd.conf.j2 @@ -0,0 +1,3 @@ +# Raise the nofile/max open files/file descriptors/file handles limit for nginx +[Service] +LimitNOFILE=30000 \ No newline at end of file diff --git a/roles/webserver/templates/php_optimization.j2 b/roles/webserver/templates/php_optimization.j2 new file mode 100644 index 0000000..f049246 --- /dev/null +++ b/roles/webserver/templates/php_optimization.j2 @@ -0,0 +1,9 @@ +## Managed by Ansible ## + +fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; +fastcgi_param PATH_INFO $path_info; +fastcgi_param HTTPS on; +fastcgi_param modHeadersAvailable true; +fastcgi_param front_controller_active true; +fastcgi_intercept_errors on; +fastcgi_request_buffering off; diff --git a/roles/webserver/templates/proxy.conf.j2 b/roles/webserver/templates/proxy.conf.j2 new file mode 100644 index 0000000..5185467 --- /dev/null +++ b/roles/webserver/templates/proxy.conf.j2 @@ -0,0 +1,15 @@ +## Managed by Ansible ## + +proxy_hide_header X-Powered-By; +proxy_set_header Early-Data $ssl_early_data; +proxy_set_header Host $host; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-Host $host; +proxy_set_header X-Forwarded-Proto $scheme; +proxy_set_header X-Forwarded-Protocol $scheme; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Port $server_port; +proxy_set_header X-Forwarded-Server $host; +proxy_redirect off; +proxy_headers_hash_max_size 1024; +proxy_headers_hash_bucket_size 128; diff --git a/roles/webserver/templates/rclone.conf.j2 b/roles/webserver/templates/rclone.conf.j2 new file mode 100644 index 0000000..9bfccaf --- /dev/null +++ b/roles/webserver/templates/rclone.conf.j2 @@ -0,0 +1,3 @@ +## Managed by Ansible ## + +{{ DTSV_GD_service_account_remote }} diff --git a/roles/webserver/vars/main.yml b/roles/webserver/vars/main.yml new file mode 100644 index 0000000..39403a5 --- /dev/null +++ b/roles/webserver/vars/main.yml @@ -0,0 +1,60 @@ +--- +# Volume +hcloud_webserver_volume_name: "WEB" +hcloud_webserver_volume_path: "/mnt/web" + +# Dependency variables +# php_old_version: "8.1" +php_version: "8.1" +php_modules: + - "fpm" + - "common" + - "curl" + - "gd" + - "gmp" + - "intl" + - "mbstring" + - "xml" + - "zip" + - "bz2" + - "bcmath" + - "imagick" + - "smbclient" + - "opcache" + - "apcu" + - "redis" + - "pgsql" + +# Main +webserver_user: "www-data" +webserver_group: "www-data" +webserver_domain: "twirling.de" + +# Nginx +webserver_nginx_cert_path: "/etc/nginx/ssl/{{ webserver_domain }}" +webserver_nginx_worker_processes: "auto" +webserver_nginx_worker_rlimit_nofile: "100000" + +# PHP +php_fpm_ini_options: + - {option: post_max_size, value: 512M} + - {option: upload_max_filesize, value: 512M} + - {option: memory_limit, value: 512M} + - {section: opcache, option: opcache.enable, value: 1} + - {section: opcache, option: opcache.interned_strings_buffer, value: 32} + - {section: opcache, option: opcache.max_accelerated_files, value: 10000} + - {section: opcache, option: opcache.memory_consumption, value: 256} + - {section: opcache, option: opcache.save_comments, value: 1} + - {section: opcache, option: opcache.revalidate_freq, value: 1} + - {section: opcache, option: opcache.validate_timestamps, value: 0} + - {section: redis, option: redis.session.locking_enabled, value: 1} + - {section: redis, option: redis.session.lock_retries, value: -1} + - {section: redis, option: redis.session.lock_wait_time, value: 10000} + +php_fpm_pool_options: + - {option: pm, value: dynamic} + - {option: pm.max_children, value: 60} + - {option: pm.start_servers, value: 20} + - {option: pm.min_spare_servers, value: 10} + - {option: pm.max_spare_servers, value: 30} + - {option: pm.max_requests, value: 1000} diff --git a/site.yml b/site.yml new file mode 100644 index 0000000..ed73e98 --- /dev/null +++ b/site.yml @@ -0,0 +1,34 @@ +--- +## Main Playbook for the staging DTSV Infrastructure + +# waiting for terraform provisioning + +- name: Wait for provisioning + hosts: label_env_prod + gather_facts: false + tasks: + - name: Wait for instance to become reachable/usable + wait_for_connection: # host_key_checking must be disabled + + - name: Gather facts + setup: + + - name: Wait for cloud-init to finish + community.general.cloud_init_data_facts: + filter: status + register: res + until: "res.cloud_init_data_facts.status.v1.stage is defined and not res.cloud_init_data_facts.status.v1.stage" + retries: 50 + delay: 5 + +# install terraformed servers + +- name: Install common packages + hosts: label_env_prod + roles: + - common + - node_exporter + become: true + +- import_playbook: db.yml +- import_playbook: web.yml diff --git a/web.yml b/web.yml new file mode 100644 index 0000000..487f8dc --- /dev/null +++ b/web.yml @@ -0,0 +1,8 @@ +--- + +- name: Install Webserver + hosts: WEB + roles: + - lego + - nextcloud + become: true