├── .gitignore ├── README.md ├── ansible.cfg ├── assets ├── reverse_proxy │ ├── .gitignore │ ├── certs │ │ └── .gitignore │ └── img │ │ ├── .gitignore │ │ ├── unifi_bg_example.png │ │ └── unifi_fg_example.png ├── rtorrent │ └── .gitignore └── stats │ └── .gitignore ├── group_vars ├── .gitignore ├── jails.yaml.template └── media.yaml.template ├── host_vars ├── .gitignore ├── dnscrypt-proxy.yaml.template ├── freenas.yaml.template ├── reverse-proxy.yaml.template ├── rtorrent.yaml.template └── stats.yaml.template ├── inventories └── hosts.yaml ├── roles ├── dnscrypt-proxy │ ├── defaults │ │ └── main.yaml │ ├── handlers │ │ └── main.yaml │ ├── tasks │ │ └── main.yaml │ └── templates │ │ └── unbound.conf ├── flood │ ├── defaults │ │ └── main.yaml │ ├── handlers │ │ └── main.yaml │ ├── meta │ │ └── main.yaml │ ├── tasks │ │ └── main.yaml │ └── templates │ │ ├── config.js │ │ ├── flood.sh │ │ └── nginx-vhost.conf ├── jails_setup │ ├── files │ │ └── sudoers_ansible │ └── tasks │ │ ├── main.yaml │ │ └── setup.yaml ├── mdns │ ├── handlers │ │ └── main.yaml │ └── tasks │ │ └── main.yaml ├── media_group │ └── tasks │ │ └── main.yaml ├── nginx │ ├── defaults │ │ └── main.yaml │ ├── handlers │ │ └── main.yaml │ ├── tasks │ │ └── main.yaml │ └── templates │ │ ├── nginx.conf │ │ └── ssl_session_cache.conf ├── php │ ├── handlers │ │ └── main.yaml │ ├── tasks │ │ └── main.yaml │ └── templates │ │ └── php.ini ├── plex │ ├── handlers │ │ └── main.yaml │ └── tasks │ │ ├── hello_hue.yaml │ │ ├── main.yaml │ │ ├── trakt_tv.yaml │ │ └── twitch_mod.yaml ├── pre_setup │ └── tasks │ │ └── main.yaml ├── radarr │ ├── handlers │ │ └── main.yaml │ └── tasks │ │ └── main.yaml ├── reverse_proxy │ ├── defaults │ │ └── main.yaml │ ├── files │ │ ├── 50x.html │ │ └── access.lua │ ├── handlers │ │ └── main.yaml │ ├── meta │ │ └── main.yaml │ ├── tasks │ │ ├── alt-domains.yaml │ │ ├── google-oauth.yaml │ │ ├── letsencrypt.yaml │ │ ├── main.yaml │ │ ├── public.yaml │ │ ├── secure.yaml │ │ └── subdirs.yaml │ └── templates │ │ ├── alt-domains-location.conf │ │ ├── alt-domains-vhost.conf │ │ ├── google-oauth.conf │ │ ├── index.html │ │ ├── letsencrypt.conf │ │ ├── proxy_params │ │ ├── public-vhost.conf │ │ ├── secure-vhost.conf │ │ ├── subdirs-location.conf │ │ └── subdirs-upstream.conf ├── rtorrent │ ├── handlers │ │ └── main.yaml │ ├── meta │ │ └── main.yaml │ ├── tasks │ │ ├── main.yaml │ │ └── nzbtomedia.yaml │ └── templates │ │ ├── autoProcessMedia.cfg │ │ ├── rtorrent.rc │ │ ├── rtorrent.sh │ │ └── set_home.sh ├── rutorrent │ ├── files │ │ └── labels │ │ │ ├── couchpotato.png │ │ │ ├── movies.png │ │ │ └── sonarr.png │ ├── meta │ │ └── main.yaml │ ├── tasks │ │ └── main.yaml │ └── templates │ │ ├── config.php │ │ ├── config.php.orig │ │ ├── nginx-vhost.conf │ │ └── php-pool.conf ├── sabnzbd │ ├── handlers │ │ └── main.yaml │ ├── meta │ │ └── main.yaml │ ├── tasks │ │ ├── main.yaml │ │ └── nzbtomedia.yaml │ └── templates │ │ ├── autoProcessMedia.cfg │ │ └── nginx-vhost.conf ├── sonarr │ ├── handlers │ │ └── main.yaml │ └── tasks │ │ └── main.yaml ├── stats │ ├── HDD stats.json │ ├── System Load.json │ ├── defaults │ │ └── main.yaml │ ├── handlers │ │ └── main.yaml │ ├── tasks │ │ └── main.yaml │ └── templates │ │ ├── grafana.conf │ │ ├── influxd.conf │ │ └── telegraf.conf └── user_customization │ ├── defaults │ └── main.yaml │ └── tasks │ └── main.yaml ├── scripts ├── backup_freenas_db.sh └── backup_jails.sh └── site.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | site.retry 2 | *.pyc 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jails configuration for FreeNAS 2 | 3 | Configure your FreeNAS jails with ansible. 4 | All software and their dependencies are automatically 5 | installed. Most of the configuration is taken care of as well, with the exception of settings only configurable through a web front-end (such as credentials for Usenet in SABnzbd). 6 | All jails have mDNS set-up, so you can access them on the internal network with `[[jailname]].local`. 7 | 8 | The jails are: 9 | 10 | * Reverse proxy 11 | * Acts as a internet facing frontend for all jail webinterfaces 12 | * Has a nice landing page where you can add links and parallax images for navigation 13 | * Automatically sets up letsencrypt 14 | * Authenticates you via your Google account 15 | * [DNSCrypt Proxy](https://github.com/jedisct1/dnscrypt-proxy) 16 | * All jails can be configured to use this one for name resolution 17 | * You can set your DHCP server to tell the rest of the network to use this jail for name resolution 18 | * [Unifi](https://unifi-sdn.ubnt.com/) server 19 | * Easy access to your Unifi AP configuration interface 20 | * Run your Unifi management software as a daemon so it can collect stats 21 | * [SABnzbd](https://sabnzbd.org/) 22 | * [rTorrent](https://github.com/rakshasa/rtorrent) + [ruTorrent](https://github.com/Novik/ruTorrent) 23 | * Contains some extra labels for ruTorrent 24 | * [Jackett](https://github.com/Jackett/Jackett) 25 | * [Sonarr](https://sonarr.tv/) 26 | * [Radarr](https://radarr.video/) 27 | * [Plex media server](https://www.plex.tv/) 28 | * Comes with [HelloHue](https://github.com/ledge74/HelloHue.bundle), [Trakt.tv](https://github.com/trakt/Plex-Trakt-Scrobbler), [TwitchMod](https://github.com/coryo/TwitchMod.bundle), [WebTools](https://github.com/ukdtom/WebTools.bundle/wiki), [YouTubeTV](https://github.com/kolsys/YouTubeTV.bundle) plugins 29 | * [Grafana](https://grafana.com/) + [Telegraf](https://github.com/influxdata/telegraf) + [InfluxDB](https://www.influxdata.com/) statistics 30 | * Supports fetching data through IPMI from your server 31 | * Can get your overall network usage through SNMP from your router (only tested with Linksys LRT214) 32 | * Can pull data from FreeNAS' own collectd service (see `host_vars/stats@freenas.local.yaml.template`, pre-made Grafana dashboard at `roles/stats/`) 33 | * Pulls all S.M.A.R.T. data from your HDDs & SSDs (also has a pre-made Grafana dashboard) 34 | * [Elasticsearch](https://www.elastic.co/products/elasticsearch) + [Kibana](https://www.elastic.co/products/kibana) [Logstash](https://www.elastic.co/products/logstash) + [Filebeat](https://www.elastic.co/products/beats/filebeat) for log aggregation 35 | * Most other jails are set up with filebeat to forward their logs to this jail (some parsing of logs and setup is still missing to see all logs in all jails) 36 | * Normalizes data from different loggers so that fields containing the same data have the same name 37 | * Can act as a rsyslog server for FreeNAS, Unifi, your router, and other devices on your network 38 | 39 | # Setup 40 | 41 | Start by creating the jails you want to create in FreeNAS. 42 | The names must match the ones used in this project, check out `inventories/hosts.yaml` 43 | for a list. Comment out any jail you are not interested in. 44 | Read the `*.template` files in `host_vars/` for instructions for the different jails 45 | and copy them to the same directory but omit `.template` part to enable them. 46 | 47 | # Backup 48 | 49 | `scripts/` contains two scripts that you can use for creating versioned backups of 50 | both your FreeNAS configuration database and the userdata of the software running in your jails. 51 | The jail backup script uses rsync with hardlinks two preserve diskspace. 52 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | # config file for ansible -- http://ansible.com/ 2 | # ============================================== 3 | 4 | # nearly all parameters can be overridden in ansible-playbook 5 | # or with command line flags. ansible will read ANSIBLE_CONFIG, 6 | # ansible.cfg in the current working directory, .ansible.cfg in 7 | # the home directory or /etc/ansible/ansible.cfg, whichever it 8 | # finds first 9 | 10 | [defaults] 11 | inventory = inventories/hosts.yaml 12 | remote_user = ansible 13 | 14 | [privilege_escalation] 15 | become = True 16 | 17 | [ssh_connection] 18 | # ssh arguments to use 19 | # Leaving off ControlPersist will result in poor performance, so use 20 | # paramiko on older platforms rather than removing it 21 | # 22 | ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s -o ForwardAgent=yes 23 | 24 | # Enabling pipelining reduces the number of SSH operations required to 25 | # execute a module on the remote server. This can result in a significant 26 | # performance improvement when enabled, however when using "sudo:" you must 27 | # first disable 'requiretty' in /etc/sudoers 28 | # 29 | # By default, this option is disabled to preserve compatibility with 30 | # sudoers configurations that have requiretty (the default on many distros). 31 | # 32 | pipelining = True 33 | -------------------------------------------------------------------------------- /assets/reverse_proxy/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !/.gitignore 3 | -------------------------------------------------------------------------------- /assets/reverse_proxy/certs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !/.gitignore 3 | -------------------------------------------------------------------------------- /assets/reverse_proxy/img/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !/.gitignore 3 | !/unifi_bg_example.png 4 | !/unifi_fg_example.png 5 | -------------------------------------------------------------------------------- /assets/reverse_proxy/img/unifi_bg_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andsens/freenas-jailconfig/60d09a7a4921ee6c132051b1f3568cee756a8a7d/assets/reverse_proxy/img/unifi_bg_example.png -------------------------------------------------------------------------------- /assets/reverse_proxy/img/unifi_fg_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andsens/freenas-jailconfig/60d09a7a4921ee6c132051b1f3568cee756a8a7d/assets/reverse_proxy/img/unifi_fg_example.png -------------------------------------------------------------------------------- /assets/rtorrent/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !/.gitignore 3 | -------------------------------------------------------------------------------- /assets/stats/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !/.gitignore 3 | -------------------------------------------------------------------------------- /group_vars/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !*.yaml.template 4 | -------------------------------------------------------------------------------- /group_vars/jails.yaml.template: -------------------------------------------------------------------------------- 1 | --- 2 | # Jails-wide configuration to customize your shell as root during `iocage console` 3 | 4 | root_shell: /usr/local/bin/zsh 5 | 6 | # Packages to install 7 | user_packages: 8 | - git 9 | - bash 10 | - zsh 11 | 12 | # Repos to clone. 13 | # Use "private: yes" to only create the repo and its remote, you can pull it later 14 | git_repos: 15 | - remote: https://github.com/andsens/homeshick.git 16 | path: /root/.homesick/repos/homeshick 17 | - remote: https://github.com/sorin-ionescu/prezto.git 18 | path: /root/.homesick/repos/prezto 19 | - remote: git@github.com:andsens/dotfiles 20 | path: /root/.homesick/repos/dotfiles 21 | private: yes 22 | -------------------------------------------------------------------------------- /group_vars/media.yaml.template: -------------------------------------------------------------------------------- 1 | sabnzbd_api_key: 0123456789abcdef0123456789abcdef 2 | sonarr_api_key: 0123456789abcdef0123456789abcdef 3 | radarr_api_key: 0123456789abcdef0123456789abcdef 4 | -------------------------------------------------------------------------------- /host_vars/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !*.yaml.template 4 | -------------------------------------------------------------------------------- /host_vars/dnscrypt-proxy.yaml.template: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | dnscrypt_resolvers: 4 | - dnscrypt.eu-dk 5 | - dnscrypt-de-blahdns-ipv4 6 | - dnscrypt.nl-ns0 7 | - dnscrypt.me 8 | - dnscrypt.uk-ipv4 9 | -------------------------------------------------------------------------------- /host_vars/freenas.yaml.template: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Unless passwordless sudo is enabled for the freenas user, provision this host with: 4 | # ANSIBLE_BECOME_ASK_PASS=true ANSIBLE_REMOTE_USER=USER ansible-playbook --limit freenas site.yml 5 | 6 | jails_path: /mnt/jails/iocage/jails 7 | jails_auth_keys: 8 | - "{{ lookup('file', '/home/USERNAME/.ssh/id_rsa.pub') }}" 9 | -------------------------------------------------------------------------------- /host_vars/reverse-proxy.yaml.template: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Consider https://github.com/GUI/nginx-upstream-dynamic-servers 4 | 5 | # In order to run nginx with the lua & ndk modules you need to compile nginx yourself 6 | # Do this by entering the jail with `sudo iocage console reverse-proxy sh` 7 | # and then running: 8 | # portsnap fetch; portsnap extract; cd /usr/ports/www/nginx; make config 9 | # Select DEVEL KIT, LUA & SET MISC in the modules prompt and answer yes to all subsequent prompts 10 | # After that run: `make install` 11 | 12 | # See https://github.com/cloudflare/nginx-google-oauth#configuring-oauth-access 13 | # for instructions on how to create a client ID and secret. 14 | # Make sure to allow all reverse_proxy_alt_domains subdomains as redirect URIs 15 | 16 | reverse_proxy_google_oauth: 17 | client_id: "CLIENTID.apps.googleusercontent.com" 18 | client_secret: "CLIENTSECRET" 19 | token_secret: "{{ lookup('password', playbook_dir ~ '/assets/reverse_proxy_google_oauth length=32 chars=ascii_letters') }}" 20 | whitelist: 21 | - example@gmail.com 22 | # nginx requires its own resolvers to be specified, set them here 23 | resolvers: 24 | - "10.134.102.1" 25 | - "8.8.8.8" 26 | - "8.8.4.4" 27 | reverse_proxy_domain: example.com 28 | reverse_proxy_alt_domains: 29 | - name: unifi 30 | domain: unifi.example.com 31 | address: 10.134.102.3:8443 32 | trust_ssl: '{{ playbook_dir }}/assets/reverse_proxy/certs/unifi.pem' 33 | # Fetch the PEM cert with 34 | # echo | openssl s_client -showcerts -servername 10.134.102.3 -connect 10.134.102.3:8443 2>/dev/null | openssl x509 -inform pem -outform pem -out assets/reverse_proxy/certs/unifi.pem 35 | - name: plex 36 | domain: plex.example.com 37 | address: 10.134.102.10:32400 38 | require_authentication: no 39 | reverse_proxy_subdirs: 40 | - name: sabnzbd 41 | address: 10.134.102.11:80 42 | forward_subdir_name: yes # determines whether the forwarded request should contain the subdir 43 | inline_config: | 44 | # Don't authenticate API access, let sabnzbd do that 45 | location /sabnzbd/api { 46 | set $ngo_enabled "false"; 47 | proxy_pass http://sabnzbd; 48 | } 49 | client_max_body_size 10M; 50 | # - name: rutorrent 51 | # address: 10.134.102.14:80 52 | - name: flood 53 | address: 10.134.102.14:80 54 | - name: jackett 55 | address: 10.134.102.16:9117 56 | - name: radarr 57 | address: 10.134.102.15:7878 58 | forward_subdir_name: yes 59 | - name: sonarr 60 | address: 10.134.102.12:8989 61 | forward_subdir_name: yes 62 | - name: stats 63 | address: 10.134.102.25:3000 64 | forward_subdir_name: no # default is no, but especially important for grafana 65 | - name: logs 66 | address: 10.134.102.26:5601 67 | forward_subdir_name: no 68 | reverse_proxy_links: 69 | - name: Unifi 70 | link: unifi/ 71 | background: '{{ playbook_dir }}/assets/reverse_proxy/img/unifi_example_bg.png' 72 | foreground: '{{ playbook_dir }}/assets/reverse_proxy/img/unifi_example_fg.png' 73 | -------------------------------------------------------------------------------- /host_vars/rtorrent.yaml.template: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Can be flood or rutorrent 4 | rtorrent_frontend: flood 5 | flood_jwt_secret: "{{ lookup('password', playbook_dir ~ '/assets/rtorrent/flood_jwt_secret length=32 chars=ascii_letters') }}" 6 | -------------------------------------------------------------------------------- /host_vars/stats.yaml.template: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # To send FreeNAS stats to InfluxDB copy the typesdb from FreeNAS to the jail: 4 | # sudo cp /usr/local/share/collectd/types.db /mnt/jails/stats/usr/local/share/collectd/types.db 5 | # Then add the following "Post Init" command in the FreeNAS console: 6 | # printf '\n Server "10.134.102.25" "25826"\n\n' >> /usr/local/etc/collectd.conf && service collectd restart 7 | # In Grafana import "roles/stats/System Load.json" to get an overview of that data 8 | 9 | grafana_root_url: https://example.com/stats 10 | grafana_secret_key: "{{ lookup('password', playbook_dir ~ '/assets/stats/grafana_secret_key length=32 chars=ascii_letters') }}" 11 | grafana_plugins: 12 | - briangann-gauge-panel 13 | telegraf_snmp: 14 | agents: ["10.134.102.1"] 15 | fields: | 16 | name = "router" 17 | [[inputs.snmp.field]] 18 | name = "hostname" 19 | oid = "SNMPv2-MIB::sysName.0" 20 | is_tag = true 21 | [[inputs.snmp.field]] 22 | name = "if7_in_octects" 23 | oid = "IF-MIB::ifInOctets.7" 24 | [[inputs.snmp.field]] 25 | name = "if7_out_octects" 26 | oid = "IF-MIB::ifOutOctets.7" 27 | [[inputs.snmp.field]] 28 | name = "if8_in_octects" 29 | oid = "IF-MIB::ifInOctets.8" 30 | [[inputs.snmp.field]] 31 | name = "if8_out_octects" 32 | oid = "IF-MIB::ifOutOctets.8" 33 | -------------------------------------------------------------------------------- /inventories/hosts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | hosts: 4 | freenas: 5 | ansible_ssh_host: freenas.local 6 | ansible_python_interpreter: /usr/local/bin/python3 7 | children: 8 | jails: 9 | hosts: 10 | reverse-proxy: 11 | ansible_ssh_host: reverse-proxy.local 12 | ansible_python_interpreter: /usr/local/bin/python3 13 | rtorrent: 14 | ansible_ssh_host: rtorrent.local 15 | ansible_python_interpreter: /usr/local/bin/python3 16 | sabnzbd: 17 | ansible_ssh_host: sabnzbd.local 18 | ansible_python_interpreter: /usr/local/bin/python3 19 | plex: 20 | ansible_ssh_host: plex.local 21 | ansible_python_interpreter: /usr/local/bin/python3 22 | sonarr: 23 | ansible_ssh_host: sonarr.local 24 | ansible_python_interpreter: /usr/local/bin/python3 25 | radarr: 26 | ansible_ssh_host: radarr.local 27 | ansible_python_interpreter: /usr/local/bin/python3 28 | dnscrypt-proxy: 29 | ansible_ssh_host: dnscrypt-proxy.local 30 | ansible_python_interpreter: /usr/local/bin/python3 31 | stats: 32 | ansible_ssh_host: stats.local 33 | ansible_python_interpreter: /usr/local/bin/python3 34 | media: 35 | hosts: 36 | rtorrent: 37 | sabnzbd: 38 | plex: 39 | sonarr: 40 | radarr: 41 | -------------------------------------------------------------------------------- /roles/dnscrypt-proxy/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | dnscrypt_resolvers: [] 4 | -------------------------------------------------------------------------------- /roles/dnscrypt-proxy/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start dnscrypt-proxy 4 | service: 5 | name: dnscrypt-proxy 6 | state: started 7 | 8 | - name: restart dnscrypt-proxy 9 | service: 10 | name: dnscrypt-proxy 11 | state: restarted 12 | 13 | - name: start unbound 14 | service: 15 | name: local_unbound 16 | state: started 17 | 18 | - name: restart unbound 19 | service: 20 | name: local_unbound 21 | state: restarted 22 | -------------------------------------------------------------------------------- /roles/dnscrypt-proxy/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install dnscrypt-proxy2 4 | pkgng: 5 | name: dnscrypt-proxy2 6 | state: present 7 | 8 | - name: install unbound 9 | pkgng: 10 | name: unbound 11 | state: present 12 | notify: restart unbound 13 | 14 | - name: configure dnscrypt-proxy resolver list 15 | lineinfile: 16 | dest: /usr/local/etc/dnscrypt-proxy/dnscrypt-proxy.toml 17 | line: server_names = {{ dnscrypt_resolvers | to_json }} 18 | regexp: ^server_names 19 | notify: restart dnscrypt-proxy 20 | tags: [config] 21 | 22 | - name: configure dnscrypt-proxy listening port 23 | lineinfile: 24 | dest: /usr/local/etc/dnscrypt-proxy/dnscrypt-proxy.toml 25 | line: listen_addresses = ['127.0.0.1:5300'] 26 | regexp: ^listen_addresses 27 | notify: restart dnscrypt-proxy 28 | tags: [config] 29 | 30 | - name: configure unbound 31 | template: 32 | src: unbound.conf 33 | dest: /var/unbound/unbound.conf 34 | owner: root 35 | group: wheel 36 | mode: 0644 37 | notify: restart unbound 38 | tags: [config] 39 | 40 | - name: enable dnscrypt-proxy 41 | service: 42 | name: dnscrypt-proxy 43 | enabled: yes 44 | notify: start dnscrypt-proxy 45 | 46 | - name: enable unbound 47 | service: 48 | name: local_unbound 49 | enabled: yes 50 | notify: start unbound 51 | -------------------------------------------------------------------------------- /roles/dnscrypt-proxy/templates/unbound.conf: -------------------------------------------------------------------------------- 1 | server: 2 | # base setup 3 | username: unbound 4 | directory: /var/unbound 5 | chroot: /var/unbound 6 | pidfile: /var/run/local_unbound.pid 7 | # DNSSEC 8 | auto-trust-anchor-file: /var/unbound/root.key 9 | # Verbose logging 10 | verbosity: 1 11 | 12 | # Listen on all interfaces and allow external lookups (i.e. LAN) 13 | interface: 0.0.0.0 14 | interface: ::0 15 | access-control: 0.0.0.0/0 allow_snoop 16 | 17 | # DNSCrypt specific setting 18 | do-not-query-localhost: no 19 | 20 | # Unblock reverse lookups for LAN addresses 21 | unblock-lan-zones: yes 22 | insecure-lan-zones: yes 23 | # Forward all queries to DNSCrypt 24 | forward-zone: 25 | name: "." 26 | forward-addr: 127.0.0.1@5300 27 | # Disable remote control 28 | remote-control: 29 | control-enable: no 30 | # Include additional files from conf.d 31 | include: /var/unbound/conf.d/*.conf 32 | -------------------------------------------------------------------------------- /roles/flood/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | flood_jwt_secret: null 4 | -------------------------------------------------------------------------------- /roles/flood/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: yarn install flood 4 | yarn: 5 | path: /usr/local/www/flood 6 | 7 | - name: yarn build flood 8 | command: yarn run build 9 | args: 10 | chdir: /usr/local/www/flood 11 | 12 | - name: start flood 13 | service: 14 | name: flood 15 | state: started 16 | 17 | - name: restart flood 18 | service: 19 | name: flood 20 | state: restarted 21 | -------------------------------------------------------------------------------- /roles/flood/meta/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | dependencies: 4 | - role: nginx 5 | -------------------------------------------------------------------------------- /roles/flood/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install flood dependencies 4 | pkgng: 5 | name: 6 | - node 7 | - yarn 8 | state: present 9 | 10 | - name: create flood user 11 | user: 12 | name: flood 13 | groups: 14 | - media 15 | - rtorrent 16 | state: present 17 | home: /usr/local/www/flood 18 | createhome: no 19 | 20 | - name: add the flood user to the rtorrent group 21 | user: 22 | name: flood 23 | groups: rtorrent 24 | append: yes 25 | notify: restart flood 26 | 27 | - name: add the www user to the rtorrent group 28 | user: 29 | name: www 30 | groups: rtorrent 31 | append: yes 32 | notify: restart nginx 33 | 34 | - name: create flood webdir 35 | file: 36 | path: /usr/local/www/flood 37 | state: directory 38 | owner: root 39 | group: wheel 40 | mode: 0755 41 | 42 | - name: clone flood 43 | git: 44 | repo: https://github.com/jfurrow/flood.git 45 | dest: /usr/local/www/flood 46 | version: 61b63e9b549b4ae92796b5595f583e4cff388a13 47 | update: yes 48 | force: yes 49 | notify: 50 | - yarn install flood 51 | - yarn build flood 52 | 53 | - name: set owner of server/db/ to flood 54 | file: 55 | path: /usr/local/www/flood/server/db 56 | state: directory 57 | recurse: yes 58 | owner: flood 59 | group: wheel 60 | mode: 'u=rwX,go=rX' 61 | 62 | - name: configure flood 63 | template: 64 | src: config.js 65 | dest: /usr/local/www/flood/config.js 66 | owner: root 67 | group: wheel 68 | mode: 0644 69 | notify: 70 | - yarn build flood 71 | tags: [config] 72 | 73 | - name: create flood init script 74 | template: 75 | src: flood.sh 76 | dest: /usr/local/etc/rc.d/flood 77 | owner: root 78 | group: wheel 79 | mode: 0755 80 | notify: restart flood 81 | 82 | - name: enable flood 83 | service: 84 | name: flood 85 | enabled: yes 86 | notify: start flood 87 | 88 | - name: create the nginx vhost 89 | template: 90 | src: nginx-vhost.conf 91 | dest: /usr/local/etc/nginx/sites-available/flood 92 | owner: root 93 | group: wheel 94 | mode: 0644 95 | notify: reload nginx 96 | tags: [config] 97 | 98 | - name: disable rutorrent vhost 99 | file: 100 | path: /usr/local/etc/nginx/sites-enabled/rutorrent 101 | state: absent 102 | notify: reload nginx 103 | 104 | - name: enable the vhost 105 | file: 106 | src: /usr/local/etc/nginx/sites-available/flood 107 | dest: /usr/local/etc/nginx/sites-enabled/flood 108 | state: link 109 | notify: reload nginx 110 | -------------------------------------------------------------------------------- /roles/flood/templates/config.js: -------------------------------------------------------------------------------- 1 | // This is the configuration file for Flood, a React-based frontend for the 2 | // rtorrent BitTorrent client. 3 | // Copy this file to ./config.js and make changes below. 4 | // config.js must exist before running `npm run build`. 5 | 6 | const CONFIG = { 7 | // This URI will prefix all of Flood's HTTP requests. You _must_ have a web 8 | // server, like nginx, configured to forward these requests to the Flood 9 | // web server. 10 | // For example, if you intend to serve from http://example.com/flood, set this to 11 | // '/flood' and configure your web server to pass _all_ requests from `/flood` to 12 | // the root of Flood's web server. 13 | // Recompiling assets with `npm run build` is needed after each `baseURI` change. 14 | // See https://github.com/jfurrow/flood/wiki/Using-Flood-behind-a-reverse-proxy 15 | baseURI: '/flood', 16 | // Flood uses a local nedb database to keep track of users, torrents, 17 | // and activity. The database is regularly purged to remove outdated data. 18 | // This value dictates how old data is, in milliseconds, before being purged. 19 | dbCleanInterval: 1000 * 60 * 60, 20 | // Where to store the local nedb database. 21 | dbPath: './server/db/', 22 | // The host that Flood should listen for web connections on. 23 | // If you want to connect to Flood from hosts other that the one it is running 24 | // on, you should change this value. 25 | // To listen on all interfaces, change to `floodServerHost: '0.0.0.0'`.. 26 | floodServerHost: '127.0.0.1', 27 | // The port that Flood should listen for web connections on. 28 | floodServerPort: 3000, 29 | // Used for development. See the "Local Development" section of README.md 30 | // for detail. 31 | floodServerProxy: 'http://127.0.0.1:3000', 32 | // Flood keeps a history of torrent download and upload speeds. 33 | // This value dictates the number of individual records per period to keep. 34 | maxHistoryStates: 30, 35 | // How often (in milliseconds) Flood will request the torrent list from. 36 | torrentClientPollInterval: 1000 * 2, 37 | // A unique secret for signing messages with JWT (see https://jwt.io). Change 38 | // this to something unique and hard to guess. 39 | secret: '{{ flood_jwt_secret }}', 40 | // Configuration for SSL, if using SSL with the Flood service directly. 41 | ssl: false, 42 | sslKey: '/absolute/path/to/key/', 43 | sslCert: '/absolute/path/to/certificate/' 44 | }; 45 | // Do not remove the below line. 46 | module.exports = CONFIG; 47 | -------------------------------------------------------------------------------- /roles/flood/templates/flood.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: flood 4 | # REQUIRE: DAEMON cleanvar 5 | # KEYWORD: shutdown 6 | 7 | . /etc/rc.subr 8 | 9 | flood_home=/usr/local/www/flood 10 | flood_bin=/usr/local/www/flood/server/bin/start.js 11 | 12 | name=flood 13 | rcvar=flood_enable 14 | pidfile="/var/run/${name}.pid" 15 | logfile="/var/log/${name}.log" 16 | command="/usr/sbin/daemon" 17 | command_args="-o ${logfile} -P ${pidfile} -t ${name} -u flood /usr/local/bin/node ${flood_bin}" 18 | flood_chdir=${flood_home} 19 | argument_precmd= 20 | 21 | load_rc_config $name 22 | export PATH="$PATH:/usr/local/bin" 23 | run_rc_command "$@" 24 | -------------------------------------------------------------------------------- /roles/flood/templates/nginx-vhost.conf: -------------------------------------------------------------------------------- 1 | upstream flood { 2 | server localhost:3000; 3 | } 4 | upstream rtorrent { 5 | server unix:/usr/local/libdata/rtorrent/rpc.socket; 6 | } 7 | server { 8 | listen 80; 9 | location /RPC2 { 10 | include scgi_params; 11 | scgi_param SCRIPT_NAME /RPC2; 12 | scgi_pass rtorrent; 13 | } 14 | location /flood/ { 15 | proxy_pass http://flood/; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /roles/jails_setup/files/sudoers_ansible: -------------------------------------------------------------------------------- 1 | Defaults:ansible !requiretty 2 | ansible ALL=(ALL) NOPASSWD: ALL 3 | -------------------------------------------------------------------------------- /roles/jails_setup/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - include_tasks: setup.yaml 4 | loop_control: 5 | label: "{{ jail_name }}" 6 | loop_var: jail_name 7 | loop: "{{ groups['jails'] }}" 8 | -------------------------------------------------------------------------------- /roles/jails_setup/tasks/setup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: initialize pkg 4 | command: iocage exec {{ jail_name }} env ASSUME_ALWAYS_YES=true pkg update 5 | 6 | - name: enable sshd 7 | lineinfile: 8 | dest: "{{ jails_path }}/{{ jail_name }}/root/etc/defaults/rc.conf" 9 | line: sshd_enable="YES" 10 | regexp: ^sshd_enable 11 | register: sshd_conf_result 12 | tags: [config] 13 | become: yes 14 | 15 | - name: start sshd 16 | command: iocage exec {{ jail_name }} service sshd start 17 | become: yes 18 | when: sshd_conf_result is changed 19 | 20 | - name: create the ansible user 21 | command: iocage exec {{ jail_name }} pw useradd ansible 22 | args: 23 | creates: "{{ jails_path }}/{{ jail_name }}/root/home/ansible" 24 | become: yes 25 | 26 | - name: create ssh dir for ansible user 27 | file: 28 | path: "{{ jails_path }}/{{ jail_name }}/root/home/ansible/.ssh" 29 | state: directory 30 | mode: 0755 31 | become: yes 32 | 33 | - name: chown home dir to ansible user 34 | command: iocage exec {{ jail_name }} chown -R ansible:ansible "/home/ansible" 35 | become: yes 36 | 37 | # The authorized_key module expects the user to exist, which it does, 38 | # but only in the jail. So we use lineinfile as a low-lelvel solution instead. 39 | - name: setup authorized_keys for ansible user 40 | lineinfile: 41 | dest: "{{ jails_path }}/{{ jail_name }}/root/home/ansible/.ssh/authorized_keys" 42 | line: "{{ key }}" 43 | create: yes 44 | loop: "{{ jails_auth_keys }}" 45 | loop_control: 46 | loop_var: key 47 | label: "{{ key.split()[-1] }}" 48 | 49 | - name: chown authorized_keys to ansible user 50 | command: iocage exec {{ jail_name }} chown ansible:ansible "/home/ansible/.ssh/authorized_keys" 51 | become: yes 52 | 53 | - name: install sudo 54 | command: iocage exec {{ jail_name }} pkg install -y sudo 55 | become: yes 56 | 57 | - name: allow ansible to do passwordless sudo 58 | copy: 59 | src: sudoers_ansible 60 | dest: "{{ jails_path }}/{{ jail_name }}/root/usr/local/etc/sudoers.d/50_ansible" 61 | mode: 0440 62 | owner: root 63 | group: wheel 64 | become: yes 65 | 66 | - name: install python3 67 | command: iocage exec {{ jail_name }} pkg install -y python3 68 | become: yes 69 | -------------------------------------------------------------------------------- /roles/mdns/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start avahi 4 | service: 5 | name: avahi-daemon 6 | state: started 7 | pattern: avahi-daemon 8 | 9 | - name: restart avahi 10 | service: 11 | name: avahi-daemon 12 | state: restarted 13 | pattern: avahi-daemon 14 | 15 | - name: start dbus 16 | service: 17 | name: dbus 18 | state: started 19 | 20 | - name: restart dbus 21 | service: 22 | name: dbus 23 | state: restarted 24 | -------------------------------------------------------------------------------- /roles/mdns/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install mdns-daemon 4 | pkgng: 5 | name: dns/mdnsd 6 | state: present 7 | 8 | - name: install nss_mdns 9 | pkgng: 10 | name: dns/nss_mdns 11 | state: present 12 | 13 | - name: enable mdns resolution 14 | lineinfile: 15 | dest: /etc/nsswitch.conf 16 | regexp: "^hosts:" 17 | line: "hosts: files dns mdns" 18 | tags: [config] 19 | 20 | - name: enable dbus 21 | service: 22 | name: dbus 23 | enabled: yes 24 | notify: start dbus 25 | 26 | - name: flush handlers to ensure dbus is started before avahi-daemon 27 | meta: flush_handlers 28 | 29 | - name: enable avahi-daemon 30 | service: 31 | name: avahi-daemon 32 | enabled: yes 33 | pattern: avahi-daemon 34 | notify: start avahi 35 | -------------------------------------------------------------------------------- /roles/media_group/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: create the media group 4 | group: 5 | name: media 6 | gid: 8675309 7 | state: present 8 | -------------------------------------------------------------------------------- /roles/nginx/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | nginx_ssl: no 4 | -------------------------------------------------------------------------------- /roles/nginx/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start nginx 4 | service: 5 | name: nginx 6 | state: started 7 | 8 | - name: restart nginx 9 | service: 10 | name: nginx 11 | state: restarted 12 | 13 | - name: reload nginx 14 | service: 15 | name: nginx 16 | state: reloaded 17 | -------------------------------------------------------------------------------- /roles/nginx/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install nginx 4 | pkgng: 5 | name: nginx 6 | state: present 7 | become: yes 8 | 9 | - name: clear out nginx default www files 10 | file: 11 | path: /usr/local/www/{{ item }} 12 | state: absent 13 | loop: 14 | - nginx 15 | - nginx-dist 16 | become: yes 17 | 18 | - name: create nginx config folders 19 | file: 20 | path: /usr/local/etc/nginx/{{ item }} 21 | state: directory 22 | owner: root 23 | group: wheel 24 | mode: 0755 25 | loop: 26 | - conf.d 27 | - sites-available 28 | - sites-enabled 29 | - mods-available 30 | - mods-enabled 31 | become: yes 32 | 33 | - name: configure nginx 34 | template: 35 | src: nginx.conf 36 | dest: /usr/local/etc/nginx/nginx.conf 37 | owner: root 38 | group: wheel 39 | mode: 0644 40 | notify: reload nginx 41 | tags: [config] 42 | become: yes 43 | 44 | - name: configure nginx ssl session cache 45 | template: 46 | src: ssl_session_cache.conf 47 | dest: /usr/local/etc/nginx/conf.d/ssl_session_cache.conf 48 | owner: root 49 | group: wheel 50 | mode: 0644 51 | notify: reload nginx 52 | when: nginx_ssl 53 | tags: [config] 54 | become: yes 55 | 56 | - name: generate diffie-hellman group 57 | command: openssl dhparam -out /usr/local/etc/nginx/dhparams.pem 2048 58 | args: 59 | creates: /usr/local/etc/nginx/dhparams.pem 60 | notify: reload nginx 61 | when: nginx_ssl 62 | become: yes 63 | 64 | - name: enable nginx 65 | service: 66 | name: nginx 67 | enabled: yes 68 | notify: start nginx 69 | become: yes 70 | -------------------------------------------------------------------------------- /roles/nginx/templates/nginx.conf: -------------------------------------------------------------------------------- 1 | include mods-enabled/*.load; 2 | 3 | user www; 4 | worker_processes 1; 5 | pid /var/run/nginx.pid; 6 | 7 | events { 8 | worker_connections 1024; 9 | multi_accept on; 10 | } 11 | 12 | http { 13 | sendfile on; 14 | tcp_nopush on; 15 | tcp_nodelay on; 16 | keepalive_timeout 65; 17 | types_hash_max_size 2048; 18 | server_tokens off; 19 | 20 | include mime.types; 21 | default_type application/octet-stream; 22 | 23 | access_log /var/log/nginx-access.log; 24 | error_log /var/log/nginx-error.log; 25 | 26 | include conf.d/*.conf; 27 | include sites-enabled/*; 28 | } 29 | -------------------------------------------------------------------------------- /roles/nginx/templates/ssl_session_cache.conf: -------------------------------------------------------------------------------- 1 | # Enable SSL session caching for improved performance 2 | # http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_session_cache 3 | ssl_session_cache shared:ssl_session_cache:10m; 4 | -------------------------------------------------------------------------------- /roles/php/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start php-fpm 4 | service: 5 | name: php-fpm 6 | state: started 7 | 8 | - name: restart php-fpm 9 | service: 10 | name: php-fpm 11 | state: restarted 12 | -------------------------------------------------------------------------------- /roles/php/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install php 4 | pkgng: 5 | name: php56 6 | state: present 7 | 8 | - name: install php extensions 9 | pkgng: 10 | name: php56-extensions 11 | state: present 12 | notify: restart php-fpm 13 | 14 | - name: configure php 15 | template: 16 | src: php.ini 17 | dest: /usr/local/etc/php.ini 18 | owner: root 19 | group: wheel 20 | mode: 0644 21 | notify: restart php-fpm 22 | tags: [config] 23 | 24 | - name: enable php-fpm 25 | service: 26 | name: php-fpm 27 | enabled: yes 28 | notify: start php-fpm 29 | -------------------------------------------------------------------------------- /roles/plex/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start plex 4 | service: 5 | name: plexmediaserver 6 | state: started 7 | 8 | - name: restart plex 9 | service: 10 | name: plexmediaserver 11 | state: restarted 12 | -------------------------------------------------------------------------------- /roles/plex/tasks/hello_hue.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: download hello hue 4 | get_url: 5 | url: https://github.com/ledge74/HelloHue.bundle/archive/37ea90faf2fdf8d3badddfb5466173329e8e6122.tar.gz 6 | dest: /usr/local/libdata/ansible/downloads/hello-hue-37ea90fa.tar.gz 7 | sha256sum: 00ec7aa1d5da3657419a57b36282273081fed044319d2ac16c2d9ce8b21222b3 8 | register: hello_hue_downloaded 9 | 10 | - name: create hello hue bundle dir 11 | file: 12 | path: "/usr/local/plexdata/Plex Media Server/Plug-ins/HelloHue.bundle" 13 | state: directory 14 | 15 | - name: install hello hue 16 | command: tar -xvzf /usr/local/libdata/ansible/downloads/hello-hue-37ea90fa.tar.gz 17 | -C "/usr/local/plexdata/Plex Media Server/Plug-ins/HelloHue.bundle" 18 | --strip-components 1 19 | HelloHue.bundle-37ea90faf2fdf8d3badddfb5466173329e8e6122 20 | # args: 21 | # creates: "/usr/local/plexdata/Plex Media Server/Plug-ins/HelloHue.bundle/README.md" 22 | when: hello_hue_downloaded|changed 23 | notify: restart plex 24 | 25 | - name: change owner of the hello hue plugin code to plex 26 | file: 27 | path: '/usr/local/plexdata/Plex Media Server/Plug-ins/HelloHue.bundle' 28 | state: directory 29 | recurse: yes 30 | owner: plex 31 | group: plex 32 | mode: 'u=rwX,go=rX' 33 | -------------------------------------------------------------------------------- /roles/plex/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install plex 4 | pkgng: 5 | name: plexmediaserver 6 | state: present 7 | 8 | - name: flush handlers to start plex (plexdata dir needed in other tasks) 9 | meta: flush_handlers 10 | 11 | - name: install trakt tv plugin 12 | include: trakt_tv.yaml 13 | 14 | - name: install hello hue plugin 15 | include: hello_hue.yaml 16 | 17 | - name: install twitch mod plugin 18 | include: twitch_mod.yaml 19 | 20 | - name: enable plex 21 | service: 22 | name: plexmediaserver 23 | enabled: yes 24 | notify: start plex 25 | -------------------------------------------------------------------------------- /roles/plex/tasks/trakt_tv.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: download trakt tv 4 | get_url: 5 | url: https://github.com/trakt/Plex-Trakt-Scrobbler/archive/f9dc5ec3cf7fab07e6a5128f082d82d96dd170ad.tar.gz 6 | dest: /usr/local/libdata/ansible/downloads/trakt-tv-a6ab5f41.tar.gz 7 | sha256sum: bb3a37db7ac5c5f21306ce36e7491908a1e8ce48b02fb65f64ea14d54ce09f66 8 | register: trakt_tv_downloaded 9 | 10 | - name: create trakt tv bundle dir 11 | file: 12 | path: "/usr/local/plexdata/Plex Media Server/Plug-ins/Trakttv.bundle" 13 | state: directory 14 | 15 | - name: install trakt tv 16 | command: tar -xvzf /usr/local/libdata/ansible/downloads/trakt-tv-a6ab5f41.tar.gz 17 | -C "/usr/local/plexdata/Plex Media Server/Plug-ins/Trakttv.bundle" 18 | --strip-components 2 19 | Plex-Trakt-Scrobbler-f9dc5ec3cf7fab07e6a5128f082d82d96dd170ad/Trakttv.bundle 20 | # args: 21 | # creates: "/usr/local/plexdata/Plex Media Server/Plug-ins/Trakttv.bundle/CREDITS.md" 22 | when: trakt_tv_downloaded|changed 23 | notify: restart plex 24 | 25 | - name: change owner of the trakt tv plugin code to plex 26 | file: 27 | path: '/usr/local/plexdata/Plex Media Server/Plug-ins/Trakttv.bundle' 28 | state: directory 29 | recurse: yes 30 | owner: plex 31 | group: plex 32 | mode: 'u=rwX,go=rX' 33 | -------------------------------------------------------------------------------- /roles/plex/tasks/twitch_mod.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: download twitch mod 4 | get_url: 5 | url: https://github.com/coryo/TwitchMod.bundle/archive/6aecc72bfde03c94225901daaa5834a4b867a1ad.tar.gz 6 | dest: /usr/local/libdata/ansible/downloads/twitch-mod-6aecc72b.tar.gz 7 | sha256sum: f05762b43c4c557af44c7dfd7d6f91cd82d8c5efb1f87f3f40cd664f7b922213 8 | register: twitch_mod_downloaded 9 | 10 | - name: create twitch mod bundle dir 11 | file: 12 | path: "/usr/local/plexdata/Plex Media Server/Plug-ins/TwitchMod.bundle" 13 | state: directory 14 | 15 | - name: install twitch mod 16 | command: tar -xvzf /usr/local/libdata/ansible/downloads/twitch-mod-6aecc72b.tar.gz 17 | -C "/usr/local/plexdata/Plex Media Server/Plug-ins/TwitchMod.bundle" 18 | --strip-components 1 19 | TwitchMod.bundle-6aecc72bfde03c94225901daaa5834a4b867a1ad 20 | # args: 21 | # creates: "/usr/local/plexdata/Plex Media Server/Plug-ins/TwitchMod.bundle/README.md" 22 | when: twitch_mod_downloaded|changed 23 | notify: restart plex 24 | 25 | - name: change owner of the twitch mod plugin code to plex 26 | file: 27 | path: '/usr/local/plexdata/Plex Media Server/Plug-ins/TwitchMod.bundle' 28 | state: directory 29 | recurse: yes 30 | owner: plex 31 | group: plex 32 | mode: 'u=rwX,go=rX' 33 | -------------------------------------------------------------------------------- /roles/pre_setup/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: create ansible dirs 4 | file: 5 | path: /usr/local/libdata/{{ item }} 6 | state: directory 7 | mode: 0755 8 | owner: root 9 | group: wheel 10 | loop: 11 | - ansible 12 | - ansible/downloads 13 | - ansible/archives 14 | become: yes 15 | -------------------------------------------------------------------------------- /roles/radarr/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start radarr 4 | service: 5 | name: radarr 6 | state: started 7 | 8 | - name: restart radarr 9 | service: 10 | name: radarr 11 | state: restarted 12 | -------------------------------------------------------------------------------- /roles/radarr/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install radarr 4 | pkgng: 5 | name: radarr 6 | state: present 7 | 8 | - name: add the radarr user to the media group 9 | user: 10 | name: radarr 11 | groups: media 12 | append: yes 13 | notify: restart radarr 14 | 15 | - name: allow radarr to auto-update 16 | file: 17 | path: /usr/local/share/radarr 18 | state: directory 19 | recurse: yes 20 | owner: radarr 21 | group: wheel 22 | mode: 'u=rwX,go=rX' 23 | 24 | - name: enable radarr 25 | service: 26 | name: radarr 27 | enabled: yes 28 | notify: start radarr 29 | -------------------------------------------------------------------------------- /roles/reverse_proxy/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | reverse_proxy_domain: null 4 | reverse_proxy_alt_domains: [] 5 | reverse_proxy_subdirs: [] 6 | reverse_proxy_links: [] 7 | reverse_proxy_google_oauth: 8 | client_id: null 9 | client_secret: null 10 | token_secret: null 11 | whitelist: null 12 | resolvers: null 13 | -------------------------------------------------------------------------------- /roles/reverse_proxy/files/50x.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 12 | 13 | 14 |

An error occurred.

15 |

Sorry, the page you are looking for is currently unavailable.
16 | Please try again later.

17 |

If you are the system administrator of this resource then you should check 18 | the error log for details.

19 |

Faithfully yours, nginx.

20 | 21 | 22 | -------------------------------------------------------------------------------- /roles/reverse_proxy/files/access.lua: -------------------------------------------------------------------------------- 1 | -- From: https://github.com/cloudflare/nginx-google-oauth (modified to support ngo_enabled) 2 | -- Copyright 2015-2016 CloudFlare 3 | -- Copyright 2014-2015 Aaron Westendorf 4 | 5 | local json = require("cjson") 6 | local http = require("resty.http") 7 | 8 | local uri = ngx.var.uri 9 | local uri_args = ngx.req.get_uri_args() 10 | local scheme = ngx.var.scheme 11 | 12 | local enabled = ngx.var.ngo_enabled ~= "false" or false 13 | local client_id = ngx.var.ngo_client_id 14 | local client_secret = ngx.var.ngo_client_secret 15 | local token_secret = ngx.var.ngo_token_secret 16 | local domain = ngx.var.ngo_domain 17 | local cb_scheme = ngx.var.ngo_callback_scheme or scheme 18 | local cb_server_name = ngx.var.ngo_callback_host 19 | local cb_uri = ngx.var.ngo_callback_uri or "/_oauth" 20 | local cb_url = cb_scheme .. "://" .. cb_server_name .. cb_uri 21 | local redirect_url = cb_scheme .. "://" .. cb_server_name .. ngx.var.request_uri 22 | local signout_uri = ngx.var.ngo_signout_uri or "/_signout" 23 | local extra_validity = tonumber(ngx.var.ngo_extra_validity or "0") 24 | local whitelist = ngx.var.ngo_whitelist or "" 25 | local blacklist = ngx.var.ngo_blacklist or "" 26 | local secure_cookies = ngx.var.ngo_secure_cookies == "true" or false 27 | local set_user = ngx.var.ngo_user or false 28 | local email_as_user = ngx.var.ngo_email_as_user == "true" or false 29 | 30 | if whitelist:len() == 0 then 31 | whitelist = nil 32 | end 33 | 34 | if blacklist:len() == 0 then 35 | blacklist = nil 36 | end 37 | 38 | local function handle_token_uris(email, token, expires) 39 | if uri == "/_token.json" then 40 | ngx.header["Content-type"] = "application/json" 41 | ngx.say(json.encode({ 42 | email = email, 43 | token = token, 44 | expires = expires, 45 | })) 46 | ngx.exit(ngx.OK) 47 | end 48 | 49 | if uri == "/_token.txt" then 50 | ngx.header["Content-type"] = "text/plain" 51 | ngx.say("email: " .. email .. "\n" .. "token: " .. token .. "\n" .. "expires: " .. expires .. "\n") 52 | ngx.exit(ngx.OK) 53 | end 54 | 55 | if uri == "/_token.curl" then 56 | ngx.header["Content-type"] = "text/plain" 57 | ngx.say("-H \"OauthEmail: " .. email .. "\" -H \"OauthAccessToken: " .. token .. "\" -H \"OauthExpires: " .. expires .. "\"\n") 58 | ngx.exit(ngx.OK) 59 | end 60 | end 61 | 62 | 63 | local function on_auth(email, token, expires) 64 | local oauth_domain = email:match("[^@]+@(.+)") 65 | 66 | if not (whitelist or blacklist) then 67 | if domain:len() ~= 0 then 68 | if oauth_domain ~= domain then 69 | ngx.log(ngx.ERR, email .. " is not on " .. domain) 70 | return ngx.exit(ngx.HTTP_FORBIDDEN) 71 | end 72 | end 73 | end 74 | 75 | if whitelist then 76 | if not string.find(" " .. whitelist .. " ", " " .. email .. " ") then 77 | ngx.log(ngx.ERR, email .. " is not in whitelist") 78 | return ngx.exit(ngx.HTTP_FORBIDDEN) 79 | end 80 | end 81 | 82 | if blacklist then 83 | if string.find(" " .. blacklist .. " ", " " .. email .. " ") then 84 | ngx.log(ngx.ERR, email .. " is in blacklist") 85 | return ngx.exit(ngx.HTTP_FORBIDDEN) 86 | end 87 | end 88 | 89 | if set_user then 90 | if email_as_user then 91 | ngx.var.ngo_user = email 92 | else 93 | ngx.var.ngo_user = email:match("([^@]+)@.+") 94 | end 95 | end 96 | 97 | handle_token_uris(email, token, expires) 98 | end 99 | 100 | local function request_access_token(code) 101 | local request = http.new() 102 | 103 | request:set_timeout(7000) 104 | 105 | local res, err = request:request_uri("https://accounts.google.com/o/oauth2/token", { 106 | method = "POST", 107 | body = ngx.encode_args({ 108 | code = code, 109 | client_id = client_id, 110 | client_secret = client_secret, 111 | redirect_uri = cb_url, 112 | grant_type = "authorization_code", 113 | }), 114 | headers = { 115 | ["Content-type"] = "application/x-www-form-urlencoded" 116 | }, 117 | ssl_verify = true, 118 | }) 119 | if not res then 120 | return nil, (err or "auth token request failed: " .. (err or "unknown reason")) 121 | end 122 | 123 | if res.status ~= 200 then 124 | return nil, "received " .. res.status .. " from https://accounts.google.com/o/oauth2/token: " .. res.body 125 | end 126 | 127 | return json.decode(res.body) 128 | end 129 | 130 | local function request_profile(token) 131 | local request = http.new() 132 | 133 | request:set_timeout(7000) 134 | 135 | local res, err = request:request_uri("https://www.googleapis.com/oauth2/v2/userinfo", { 136 | headers = { 137 | ["Authorization"] = "Bearer " .. token, 138 | }, 139 | ssl_verify = true, 140 | }) 141 | if not res then 142 | return nil, "auth info request failed: " .. (err or "unknown reason") 143 | end 144 | 145 | if res.status ~= 200 then 146 | return nil, "received " .. res.status .. " from https://www.googleapis.com/oauth2/v2/userinfo" 147 | end 148 | 149 | return json.decode(res.body) 150 | end 151 | 152 | local function is_authorized() 153 | local headers = ngx.req.get_headers() 154 | 155 | local expires = tonumber(ngx.var.cookie_OauthExpires) or 0 156 | local email = ngx.unescape_uri(ngx.var.cookie_OauthEmail or "") 157 | local token = ngx.unescape_uri(ngx.var.cookie_OauthAccessToken or "") 158 | 159 | if expires == 0 and headers["oauthexpires"] then 160 | expires = tonumber(headers["oauthexpires"]) 161 | end 162 | 163 | if email:len() == 0 and headers["oauthemail"] then 164 | email = headers["oauthemail"] 165 | end 166 | 167 | if token:len() == 0 and headers["oauthaccesstoken"] then 168 | token = headers["oauthaccesstoken"] 169 | end 170 | 171 | local expected_token = ngx.encode_base64(ngx.hmac_sha1(token_secret, cb_server_name .. email .. expires)) 172 | 173 | if token == expected_token and expires and expires > ngx.time() - extra_validity then 174 | on_auth(email, expected_token, expires) 175 | return true 176 | else 177 | return false 178 | end 179 | end 180 | 181 | local function redirect_to_auth() 182 | return ngx.redirect("https://accounts.google.com/o/oauth2/auth?" .. ngx.encode_args({ 183 | client_id = client_id, 184 | scope = "email", 185 | response_type = "code", 186 | redirect_uri = cb_url, 187 | state = redirect_url, 188 | login_hint = domain, 189 | })) 190 | end 191 | 192 | local function authorize() 193 | if uri ~= cb_uri then 194 | return redirect_to_auth() 195 | end 196 | 197 | if uri_args["error"] then 198 | ngx.log(ngx.ERR, "received " .. uri_args["error"] .. " from https://accounts.google.com/o/oauth2/auth") 199 | return ngx.exit(ngx.HTTP_FORBIDDEN) 200 | end 201 | 202 | local token, token_err = request_access_token(uri_args["code"]) 203 | if not token then 204 | ngx.log(ngx.ERR, "got error during access token request: " .. token_err) 205 | return ngx.exit(ngx.HTTP_FORBIDDEN) 206 | end 207 | 208 | local profile, profile_err = request_profile(token["access_token"]) 209 | if not profile then 210 | ngx.log(ngx.ERR, "got error during profile request: " .. profile_err) 211 | return ngx.exit(ngx.HTTP_FORBIDDEN) 212 | end 213 | 214 | local expires = ngx.time() + token["expires_in"] 215 | local cookie_tail = ";version=1;path=/;Max-Age=" .. expires 216 | if secure_cookies then 217 | cookie_tail = cookie_tail .. ";secure" 218 | end 219 | 220 | local email = profile["email"] 221 | local user_token = ngx.encode_base64(ngx.hmac_sha1(token_secret, cb_server_name .. email .. expires)) 222 | 223 | on_auth(email, user_token, expires) 224 | 225 | ngx.header["Set-Cookie"] = { 226 | "OauthEmail=" .. ngx.escape_uri(email) .. cookie_tail, 227 | "OauthAccessToken=" .. ngx.escape_uri(user_token) .. cookie_tail, 228 | "OauthExpires=" .. expires .. cookie_tail, 229 | } 230 | 231 | return ngx.redirect(uri_args["state"]) 232 | end 233 | 234 | local function handle_signout() 235 | if uri == signout_uri then 236 | ngx.header["Set-Cookie"] = "OauthAccessToken==deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT" 237 | return ngx.redirect("/") 238 | end 239 | end 240 | 241 | handle_signout() 242 | 243 | if enabled and not is_authorized() then 244 | authorize() 245 | end 246 | -------------------------------------------------------------------------------- /roles/reverse_proxy/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: request letsencrypt certificate 4 | command: > 5 | /usr/local/bin/acme-client -N -n -e 6 | -C /usr/local/www/public/.well-known/acme-challenge 7 | {{ reverse_proxy_domain }} 8 | {{ reverse_proxy_alt_domains|map(attribute='domain')|join(' ') }} 9 | notify: reload nginx 10 | -------------------------------------------------------------------------------- /roles/reverse_proxy/meta/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | dependencies: 4 | - role: nginx 5 | nginx_ssl: yes 6 | -------------------------------------------------------------------------------- /roles/reverse_proxy/tasks/alt-domains.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: copy trusted certificates 4 | copy: 5 | src: "{{ item.trust_ssl }}" 6 | dest: /usr/local/etc/ssl/nginx_trusted/{{ item.trust_ssl|basename }} 7 | when: item.trust_ssl is defined 8 | notify: reload nginx 9 | loop: "{{ reverse_proxy_alt_domains }}" 10 | 11 | - name: create alternative domain vhosts 12 | template: 13 | src: alt-domains-vhost.conf 14 | dest: /usr/local/etc/nginx/sites-available/{{ item.name }} 15 | owner: root 16 | group: wheel 17 | mode: 0644 18 | notify: reload nginx 19 | loop: "{{ reverse_proxy_alt_domains }}" 20 | tags: [config] 21 | 22 | - name: enable alternative domain vhosts 23 | file: 24 | src: ../sites-available/{{ item.name }} 25 | dest: /usr/local/etc/nginx/sites-enabled/{{ item.name }} 26 | state: link 27 | notify: reload nginx 28 | loop: "{{ reverse_proxy_alt_domains }}" 29 | 30 | - name: configure alternative domain redirect locations on subdirs domain 31 | template: 32 | src: alt-domains-location.conf 33 | dest: /usr/local/etc/nginx/reverse-proxy/locations/{{ item.name }} 34 | owner: root 35 | group: wheel 36 | mode: 0644 37 | notify: reload nginx 38 | loop: "{{ reverse_proxy_alt_domains }}" 39 | tags: [config] 40 | -------------------------------------------------------------------------------- /roles/reverse_proxy/tasks/google-oauth.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # From: https://github.com/cloudflare/nginx-google-oauth 4 | 5 | - name: check if NDK module exists 6 | stat: 7 | path: /usr/local/libexec/nginx/ndk_http_module.so 8 | register: ndk_module 9 | 10 | - name: fail when NDK module doesn't exist 11 | fail: 12 | msg: > 13 | The google oauth module requires some modules to be installed 14 | that are not part of the default nginx package distribution. 15 | You need to compile nginx yourself using ports, please refer to 16 | the reverse-proxy host_vars file for instructions (they are fairly simple) 17 | when: 18 | - not ndk_module.stat.exists 19 | 20 | - name: create module loading configurations 21 | copy: 22 | content: load_module "{{ item.path }}"; 23 | dest: /usr/local/etc/nginx/mods-available/{{ item.name }}.load 24 | owner: root 25 | group: wheel 26 | mode: 0644 27 | notify: reload nginx 28 | tags: [config] 29 | loop: 30 | - name: ndk-module 31 | path: /usr/local/libexec/nginx/ndk_http_module.so 32 | - name: set-misc-module 33 | path: /usr/local/libexec/nginx/ngx_http_set_misc_module.so 34 | - name: lua-module 35 | path: /usr/local/libexec/nginx/ngx_http_lua_module.so 36 | 37 | - name: enable required nginx modules 38 | file: 39 | src: /usr/local/etc/nginx/mods-available/{{ item.name }}.load 40 | dest: /usr/local/etc/nginx/mods-enabled/{{ item.order }}-{{ item.name }}.load 41 | state: link 42 | notify: reload nginx 43 | loop: 44 | - name: ndk-module 45 | order: 10 46 | - name: set-misc-module 47 | order: 40 48 | - name: lua-module 49 | order: 60 50 | 51 | - name: install cjson lua lib 52 | pkgng: 53 | name: lua51-cjson-2.1.0 54 | state: present 55 | 56 | - name: download resty.http 57 | get_url: 58 | url: https://github.com/pintsized/lua-resty-http/archive/v0.10.tar.gz 59 | dest: /usr/local/libdata/ansible/downloads/lua-resty.http-0.10.tar.gz 60 | sha256sum: 6917ab4fd0dcd99df076e238f591aeaa9e2d7e0bca4904ebeb3c1bd418e7c1b9 61 | 62 | - name: extract resty.http 63 | command: tar -xvzf /usr/local/libdata/ansible/downloads/lua-resty.http-0.10.tar.gz 64 | -C /usr/local/libdata/ansible/downloads/ 65 | args: 66 | creates: /usr/local/libdata/ansible/downloads/lua-resty-http-0.10 67 | 68 | # *.lua files are expected to be in /usr/local/share while *.so files are expected to be in /usr/local/lib 69 | # The resty.http Makefile is a bit weird and installs its *.lua files to ../lib, 70 | # so we fix that with LUA_LIB_DIR=... 71 | - name: install resty.http 72 | command: make install LUA_INCLUDE_DIR=/usr/local/include/luajit-2.0/ LUA_LIB_DIR=/usr/local/share/luajit-2.0.5/ 73 | args: 74 | chdir: /usr/local/libdata/ansible/downloads/lua-resty-http-0.10 75 | creates: /usr/local/share/luajit-2.0.5/resty/http.lua 76 | 77 | - name: copy google-oauth lua module to nginx 78 | copy: 79 | src: access.lua 80 | dest: /usr/local/etc/nginx/reverse-proxy/google-oauth.lua 81 | owner: root 82 | group: wheel 83 | mode: 0644 84 | 85 | - name: create google-oauth module configuration 86 | template: 87 | src: google-oauth.conf 88 | dest: /usr/local/etc/nginx/reverse-proxy/google-oauth.conf 89 | owner: root 90 | group: wheel 91 | mode: 0644 92 | notify: reload nginx 93 | tags: [config] 94 | -------------------------------------------------------------------------------- /roles/reverse_proxy/tasks/letsencrypt.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install acme-client 4 | pkgng: 5 | name: acme-client 6 | state: present 7 | 8 | - name: remove the default acme challenge dir 9 | file: 10 | path: /usr/local/www/acme 11 | state: absent 12 | 13 | - name: create .well-known dir 14 | file: 15 | path: public 16 | dest: /usr/local/www/public/{{ item }} 17 | state: directory 18 | owner: root 19 | group: wheel 20 | mode: 0755 21 | loop: 22 | - .well-known 23 | - .well-known/acme-challenge 24 | 25 | - name: configure acme-client to run weekly 26 | template: 27 | src: letsencrypt.conf 28 | dest: /etc/periodic.conf 29 | owner: root 30 | group: wheel 31 | mode: 0755 32 | # config file changes might not impact the certificate 33 | # but there's no harm in running a request. 34 | # acme-client will know what's up. 35 | notify: request letsencrypt certificate 36 | tags: [config] 37 | 38 | - name: request letsencrypt certificate for the first time 39 | command: > 40 | /usr/local/bin/acme-client -N -n -e 41 | -C /usr/local/www/public/.well-known/acme-challenge 42 | {{ reverse_proxy_domain }} 43 | {{ reverse_proxy_alt_domains|map(attribute='domain')|join(' ') }} 44 | args: 45 | creates: /usr/local/etc/ssl/acme/fullchain.pem 46 | notify: reload nginx 47 | -------------------------------------------------------------------------------- /roles/reverse_proxy/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: check if reverse_proxy_domain is defined 4 | fail: 5 | msg: "reverse_proxy_domain is undefined. Set it in host_vars/reverse-proxy@freenas.local.yaml" 6 | when: reverse_proxy_domain is not defined 7 | 8 | - name: create reverse-proxy config folder 9 | file: 10 | path: /usr/local/etc/nginx/reverse-proxy 11 | state: directory 12 | owner: root 13 | group: wheel 14 | mode: 0755 15 | 16 | - name: configure public site 17 | include: public.yaml 18 | 19 | - name: flush handlers to reload nginx config 20 | meta: flush_handlers 21 | 22 | - name: configure letsencrypt 23 | include: letsencrypt.yaml 24 | 25 | - name: install nginx-google-oauth 26 | include: google-oauth.yaml 27 | 28 | - name: configure nginx proxy params 29 | template: 30 | src: proxy_params 31 | dest: /usr/local/etc/nginx/proxy_params 32 | owner: root 33 | group: wheel 34 | mode: 0644 35 | notify: reload nginx 36 | tags: [config] 37 | 38 | - name: create nginx ssl cert trust dir 39 | file: 40 | path: /usr/local/etc/ssl/nginx_trusted 41 | state: directory 42 | owner: root 43 | group: wheel 44 | mode: 0755 45 | 46 | - name: configure secure site 47 | include: secure.yaml 48 | 49 | - name: configure subdirs 50 | include: subdirs.yaml 51 | 52 | - name: configure altdomains 53 | include: alt-domains.yaml 54 | -------------------------------------------------------------------------------- /roles/reverse_proxy/tasks/public.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: create public dir 4 | file: 5 | path: /usr/local/www/public 6 | state: directory 7 | owner: root 8 | group: wheel 9 | mode: 0755 10 | 11 | - name: create 50x.html 12 | copy: 13 | src: 50x.html 14 | dest: /usr/local/www/public/50x.html 15 | owner: root 16 | group: wheel 17 | mode: 0644 18 | 19 | - name: create public vhost 20 | template: 21 | src: public-vhost.conf 22 | dest: /usr/local/etc/nginx/sites-available/public 23 | owner: root 24 | group: wheel 25 | mode: 0644 26 | notify: reload nginx 27 | tags: [config] 28 | 29 | - name: enable public vhost 30 | file: 31 | src: ../sites-available/public 32 | dest: /usr/local/etc/nginx/sites-enabled/public 33 | state: link 34 | notify: reload nginx 35 | -------------------------------------------------------------------------------- /roles/reverse_proxy/tasks/secure.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: create secure dir 4 | file: 5 | path: /usr/local/www/secure 6 | state: directory 7 | owner: root 8 | group: wheel 9 | mode: 0755 10 | 11 | - name: create 50x.html 12 | copy: 13 | src: 50x.html 14 | dest: /usr/local/www/secure/50x.html 15 | owner: root 16 | group: wheel 17 | mode: 0644 18 | 19 | - name: create index.html 20 | template: 21 | src: index.html 22 | dest: /usr/local/www/secure/index.html 23 | owner: root 24 | group: wheel 25 | mode: 0644 26 | 27 | - name: create index images dir 28 | file: 29 | path: /usr/local/www/secure/img 30 | state: directory 31 | owner: root 32 | group: wheel 33 | mode: 0755 34 | 35 | - name: copy index.html background images 36 | copy: 37 | src: "{{ item.background }}" 38 | dest: /usr/local/www/secure/img/ 39 | owner: root 40 | group: wheel 41 | mode: 0644 42 | loop: '{{ reverse_proxy_links }}' 43 | 44 | - name: copy index.html foreground images 45 | copy: 46 | src: "{{ item.foreground }}" 47 | dest: /usr/local/www/secure/img/ 48 | owner: root 49 | group: wheel 50 | mode: 0644 51 | loop: '{{ reverse_proxy_links }}' 52 | 53 | - name: create secure vhost 54 | template: 55 | src: secure-vhost.conf 56 | dest: /usr/local/etc/nginx/sites-available/secure 57 | owner: root 58 | group: wheel 59 | mode: 0644 60 | notify: reload nginx 61 | tags: [config] 62 | 63 | - name: enable secure vhost 64 | file: 65 | src: ../sites-available/secure 66 | dest: /usr/local/etc/nginx/sites-enabled/secure 67 | state: link 68 | notify: reload nginx 69 | -------------------------------------------------------------------------------- /roles/reverse_proxy/tasks/subdirs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: create reverse-proxy subdirs config structure 4 | file: 5 | path: /usr/local/etc/nginx/{{ item }} 6 | state: directory 7 | owner: root 8 | group: wheel 9 | mode: 0755 10 | loop: 11 | - reverse-proxy/locations 12 | - reverse-proxy/upstreams 13 | 14 | - name: copy trusted certificates 15 | copy: 16 | src: "{{ item.trust_ssl }}" 17 | dest: /usr/local/etc/ssl/nginx_trusted/{{ item.trust_ssl|basename }} 18 | when: item.trust_ssl is defined 19 | notify: reload nginx 20 | loop: "{{ reverse_proxy_subdirs }}" 21 | 22 | - name: configure locations 23 | template: 24 | src: "{{ item.location_template | default('subdirs-location.conf') }}" 25 | dest: /usr/local/etc/nginx/reverse-proxy/locations/{{ item.name }} 26 | owner: root 27 | group: wheel 28 | mode: 0644 29 | notify: reload nginx 30 | loop: "{{ reverse_proxy_subdirs }}" 31 | tags: [config] 32 | 33 | - name: configure upstreams 34 | template: 35 | src: subdirs-upstream.conf 36 | dest: /usr/local/etc/nginx/reverse-proxy/upstreams/{{ item.name }} 37 | owner: root 38 | group: wheel 39 | mode: 0644 40 | notify: reload nginx 41 | loop: "{{ reverse_proxy_subdirs }}" 42 | tags: [config] 43 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/alt-domains-location.conf: -------------------------------------------------------------------------------- 1 | location /{{ item.name }} { 2 | return 301 https://{{ item.domain }}/; 3 | } 4 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/alt-domains-vhost.conf: -------------------------------------------------------------------------------- 1 | upstream {{ item.name }} { 2 | server {{ item.address }}; 3 | } 4 | server { 5 | listen 443 ssl; 6 | server_name {{ item.domain }}; 7 | ssl_dhparam /usr/local/etc/nginx/dhparams.pem; 8 | ssl_certificate /usr/local/etc/ssl/acme/fullchain.pem; 9 | ssl_certificate_key /usr/local/etc/ssl/acme/private/privkey.pem; 10 | 11 | ssl_protocols TLSv1.2 TLSv1.3; 12 | ssl_prefer_server_ciphers on; 13 | ssl_ciphers "EECDH+AESGCM:EDH+AESGCM"; 14 | ssl_session_timeout 10m; 15 | add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;" always; 16 | keepalive_timeout 70; 17 | 18 | error_page 500 502 503 504 /50x.html; 19 | location / { 20 | {% if item.require_authentication|default(True) -%} 21 | # Require authentication 22 | set $ngo_callback_host "{{ item.domain }}"; 23 | include reverse-proxy/google-oauth.conf; 24 | {%- endif %} 25 | 26 | # Don't use the upstream port when redirecting 27 | port_in_redirect off; 28 | 29 | # Enable websockets, set some headers etc. 30 | include proxy_params; 31 | 32 | {% if item.trust_ssl is defined -%} 33 | proxy_ssl_trusted_certificate /usr/local/etc/ssl/nginx_trusted/{{ item.trust_ssl|basename }}; 34 | proxy_ssl_verify off; 35 | proxy_pass https://{{ item.name }}; 36 | {%- else -%} 37 | proxy_pass http://{{ item.name }}; 38 | {%- endif %} 39 | 40 | {% if item.inline_config is defined -%} 41 | {{ item.inline_config|indent(4) }} 42 | {%- endif %} 43 | 44 | access_log /var/log/nginx/{{ item.name }}-access.log; 45 | error_log /var/log/nginx/{{ item.name }}-error.log; 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/google-oauth.conf: -------------------------------------------------------------------------------- 1 | # See https://github.com/cloudflare/nginx-google-oauth/blob/master/README.md for a list of possible values 2 | set $ngo_client_id "{{ reverse_proxy_google_oauth.client_id }}"; 3 | set $ngo_client_secret "{{ reverse_proxy_google_oauth.client_secret }}"; 4 | set $ngo_token_secret "{{ reverse_proxy_google_oauth.token_secret }}"; 5 | set $ngo_secure_cookies "true"; 6 | set $ngo_whitelist "{{ reverse_proxy_google_oauth.whitelist|join(" ") }}"; 7 | set $ngo_extra_validity "432000"; 8 | set $ngo_secure_cookies "true"; 9 | 10 | # Define a resolver so that we can resolve accounts.google.com in the access script 11 | resolver {{ reverse_proxy_google_oauth.resolvers|join(" ") }} ipv6=off; 12 | 13 | # Define the CA certs location so that we can verify accounts.google.com in the access script. 14 | lua_ssl_trusted_certificate /usr/local/share/certs/ca-root-nss.crt; 15 | 16 | # Fix the default verify depth of 1, because in OpenResty world 17 | # everybody apparently signs certificates with root certs. 18 | lua_ssl_verify_depth 2; 19 | 20 | access_by_lua_file "reverse-proxy/google-oauth.lua"; 21 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Reverse Proxy 5 | 8 | 77 | 78 | 79 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/letsencrypt.conf: -------------------------------------------------------------------------------- 1 | weekly_acme_client_enable="YES" 2 | weekly_acme_client_domains="{{ reverse_proxy_domain }} {{ reverse_proxy_alt_domains|map(attribute='domain')|join(' ') }}" 3 | weekly_acme_client_challengedir="/usr/local/www/public/.well-known/acme-challenge" 4 | weekly_acme_client_args="-e" 5 | weekly_acme_client_deployscript="/usr/sbin/service nginx reload" 6 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/proxy_params: -------------------------------------------------------------------------------- 1 | proxy_http_version 1.1; 2 | proxy_set_header Host $http_host; 3 | proxy_set_header X-Real-IP $remote_addr; 4 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 5 | proxy_set_header X-Forwarded-Proto $scheme; 6 | proxy_set_header Upgrade $http_upgrade; 7 | proxy_set_header Connection "upgrade"; 8 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/public-vhost.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | root /usr/local/www/public/; 4 | error_page 500 502 503 504 /50x.html; 5 | # Redirect to https unless it is for letsencrypt 6 | if ($request_uri !~ "^/.well-known(/|/.*)$") { 7 | return 301 https://{{ reverse_proxy_domain }}$request_uri; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/secure-vhost.conf: -------------------------------------------------------------------------------- 1 | include reverse-proxy/upstreams/*; 2 | server { 3 | listen 443 ssl; 4 | server_name {{ reverse_proxy_domain }}; 5 | ssl_dhparam /usr/local/etc/nginx/dhparams.pem; 6 | ssl_certificate /usr/local/etc/ssl/acme/fullchain.pem; 7 | ssl_certificate_key /usr/local/etc/ssl/acme/private/privkey.pem; 8 | 9 | ssl_protocols TLSv1.2 TLSv1.3; 10 | ssl_prefer_server_ciphers on; 11 | ssl_ciphers "EECDH+AESGCM:EDH+AESGCM"; 12 | ssl_session_timeout 10m; 13 | add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;" always; 14 | keepalive_timeout 70; 15 | 16 | error_page 500 502 503 504 /50x.html; 17 | location / { 18 | # Require authentication 19 | set $ngo_callback_host "{{ reverse_proxy_domain }}"; 20 | include reverse-proxy/google-oauth.conf; 21 | 22 | # Don't use the upstream port when redirecting 23 | port_in_redirect off; 24 | 25 | # Enable websockets, set some headers etc. 26 | include proxy_params; 27 | 28 | root /usr/local/www/secure/; 29 | include reverse-proxy/locations/*; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/subdirs-location.conf: -------------------------------------------------------------------------------- 1 | location /{{ item.name }}/ { 2 | # Require authentication 3 | set $ngo_callback_host "{{ reverse_proxy_domain }}"; 4 | include reverse-proxy/google-oauth.conf; 5 | 6 | {% if item.trust_ssl is defined -%} 7 | proxy_ssl_trusted_certificate /usr/local/etc/ssl/nginx_trusted/{{ item.trust_ssl|basename }}; 8 | proxy_ssl_verify off; 9 | {% if item.forward_subdir_name|default(False) -%} 10 | proxy_pass https://{{ item.name }}; 11 | {%- else -%} 12 | proxy_pass https://{{ item.name }}/; 13 | {%- endif -%} 14 | {%- else -%} 15 | {% if item.forward_subdir_name|default(False) -%} 16 | proxy_pass http://{{ item.name }}; 17 | {%- else -%} 18 | proxy_pass http://{{ item.name }}/; 19 | {%- endif -%} 20 | {%- endif %} 21 | 22 | {% if item.inline_config is defined -%} 23 | {{ item.inline_config|indent(4) }} 24 | {%- endif %} 25 | 26 | access_log /var/log/nginx/{{ item.name }}-access.log; 27 | error_log /var/log/nginx/{{ item.name }}-error.log; 28 | } 29 | location /{{ item.name }} { 30 | # Redirect, URL was accessed without a trailing slash 31 | rewrite ^/{{ item.name }}$ /{{ item.name }}/ permanent; 32 | } 33 | -------------------------------------------------------------------------------- /roles/reverse_proxy/templates/subdirs-upstream.conf: -------------------------------------------------------------------------------- 1 | upstream {{ item.name }} { 2 | server {{ item.address }}; 3 | } 4 | -------------------------------------------------------------------------------- /roles/rtorrent/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start rtorrent 4 | service: 5 | name: rtorrent 6 | state: started 7 | 8 | - name: restart rtorrent 9 | service: 10 | name: rtorrent 11 | state: restarted 12 | -------------------------------------------------------------------------------- /roles/rtorrent/meta/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | dependencies: 4 | - role: rutorrent 5 | when: rtorrent_frontend == 'rutorrent' 6 | - role: flood 7 | when: rtorrent_frontend == 'flood' 8 | -------------------------------------------------------------------------------- /roles/rtorrent/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install rtorrent 4 | pkgng: 5 | name: rtorrent 6 | state: present 7 | 8 | - name: install dtach for running rtorrent 9 | pkgng: 10 | name: dtach 11 | state: present 12 | 13 | - name: create rtorrent user 14 | user: 15 | name: rtorrent 16 | groups: media 17 | state: present 18 | home: /usr/local/libdata/rtorrent 19 | createhome: no 20 | 21 | - name: create rtorrent user home dir 22 | file: 23 | path: /usr/local/libdata/rtorrent 24 | state: directory 25 | owner: rtorrent 26 | group: rtorrent 27 | mode: 0755 28 | 29 | - name: create rtorrent session dir 30 | file: 31 | path: /usr/local/libdata/rtorrent/.rtorrent.session 32 | state: directory 33 | owner: rtorrent 34 | group: rtorrent 35 | mode: 0755 36 | 37 | - name: configure rtorrent 38 | template: 39 | src: rtorrent.rc 40 | dest: /usr/local/libdata/rtorrent/.rtorrent.rc 41 | owner: rtorrent 42 | group: rtorrent 43 | mode: 0644 44 | notify: restart rtorrent 45 | tags: [config] 46 | 47 | - name: copy set_home script 48 | template: 49 | src: set_home.sh 50 | dest: /usr/local/libdata/rtorrent/set_home.sh 51 | owner: rtorrent 52 | group: rtorrent 53 | mode: 0755 54 | 55 | - name: configure nzbtomedia 56 | include: nzbtomedia.yaml 57 | 58 | - name: create rtorrent init script 59 | template: 60 | src: rtorrent.sh 61 | dest: /usr/local/etc/rc.d/rtorrent 62 | owner: root 63 | group: wheel 64 | mode: 0755 65 | notify: restart rtorrent 66 | 67 | - name: enable rtorrent 68 | service: 69 | name: rtorrent 70 | enabled: yes 71 | notify: start rtorrent 72 | -------------------------------------------------------------------------------- /roles/rtorrent/tasks/nzbtomedia.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: alias python 2.7 to python 4 | file: 5 | src: python2.7 6 | dest: /usr/local/bin/python 7 | state: link 8 | 9 | - name: install nzbtomedia dependencies 10 | pkgng: 11 | name: 12 | - py27-sqlite3 13 | - ffmpeg 14 | - unrar 15 | - unzip 16 | - p7zip 17 | state: present 18 | 19 | - name: clone nzbtomedia 20 | git: 21 | repo: https://github.com/clinton-hall/nzbToMedia.git 22 | dest: /usr/local/libdata/rtorrent/nzbtomedia 23 | version: 12.0.0 24 | update: no 25 | register: clone_nzbtomedia 26 | 27 | - name: set permissions on nzbtomedia files 28 | file: 29 | path: /usr/local/libdata/rtorrent/nzbtomedia 30 | state: directory 31 | recurse: yes 32 | owner: rtorrent 33 | group: rtorrent 34 | mode: 'u=rwX,go=rX' 35 | when: clone_nzbtomedia is changed 36 | 37 | - name: configure nzbtomedia 38 | template: 39 | src: autoProcessMedia.cfg 40 | dest: /usr/local/libdata/rtorrent/nzbtomedia/autoProcessMedia.cfg 41 | owner: rtorrent 42 | group: rtorrent 43 | mode: 0644 44 | tags: [config] 45 | -------------------------------------------------------------------------------- /roles/rtorrent/templates/autoProcessMedia.cfg: -------------------------------------------------------------------------------- 1 | # nzbToMedia Configuration 2 | # For more information, visit https://github.com/clinton-hall/nzbToMedia/wiki 3 | 4 | [General] 5 | # Enable/Disable update notifications 6 | version_notify = 1 7 | # Enable/Disable automatic updates 8 | auto_update = 1 9 | # Set to the full path to the git executable 10 | git_path = /usr/local/bin/git 11 | # GitHUB user for repo 12 | git_user = 13 | # GitHUB branch for repo 14 | git_branch = 15 | # Enable/Disable forceful cleaning of leftover files following postprocess 16 | force_clean = 0 17 | # Enable/Disable logging debug messages to nzbtomedia.log 18 | log_debug = 0 19 | # Enable/Disable logging database messages to nzbtomedia.log 20 | log_db = 0 21 | # Enable/Disable logging environment variables to debug nzbtomedia.log (helpful to track down errors calling external tools.) 22 | log_env = 0 23 | # Enable/Disable logging git output to debug nzbtomedia.log (helpful to track down update failures.) 24 | log_git = 0 25 | # Set to the directory where your ffmpeg/ffprobe executables are located 26 | ffmpeg_path = /usr/local/bin 27 | # Enable/Disable media file checking using ffprobe. 28 | check_media = 1 29 | # Enable/Disable a safety check to ensure we don't process all downloads in the default_downloadDirectories by mistake. 30 | safe_mode = 1 31 | # Turn this on to disable additional extraction attempts for failed downloads. Default = 0 will attempt to extract and verify if media is present. 32 | no_extract_failed = 0 33 | 34 | [Posix] 35 | ### Process priority setting for External commands (Extractor and Transcoder) on Posix (Unix/Linux/OSX) systems. 36 | # Set the Niceness value for the nice command. These range from -20 (most favorable to the process) to 19 (least favorable to the process). 37 | niceness = 0 38 | # Set the ionice scheduling class. 0 for none, 1 for real time, 2 for best-effort, 3 for idle. 39 | ionice_class = 0 40 | # Set the ionice scheduling class data. This defines the class data, if the class accepts an argument. For real time and best-effort, 0-7 is valid data. 41 | ionice_classdata = 0 42 | 43 | [Windows] 44 | ### Set specific settings for Windows systems 45 | # Set this to 1 to allow extraction (7zip) windows to be lunched visble (for debugging) otherwise 0 to have this run in background. 46 | show_extraction = 0 47 | 48 | [CouchPotato] 49 | #### autoProcessing for Movies 50 | #### movie - category that gets called for post-processing with CPS 51 | [[movie]] 52 | enabled = 0 53 | apikey = 54 | host = localhost 55 | port = 5050 56 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 57 | ssl = 0 58 | web_root = 59 | # api key for www.omdbapi.com (used as alternative to imdb) 60 | omdbapikey = 61 | # Enable/Disable linking for Torrents 62 | Torrent_NoLink = 0 63 | keep_archive = 1 64 | method = renamer 65 | delete_failed = 0 66 | wait_for = 2 67 | extract = 1 68 | # Set this to minimum required size to consider a media file valid (in MB) 69 | minSize = 0 70 | # Enable/Disable deleting ignored files (samples and invalid media files) 71 | delete_ignored = 0 72 | ##### Enable if Couchpotato is on a remote server for this category 73 | remote_path = 0 74 | ##### Set to path where download client places completed downloads locally for this category 75 | watch_dir = 76 | ##### Set the recursive directory permissions to the following (0 to disable) 77 | chmodDirectory = 0 78 | 79 | [Radarr] 80 | #### autoProcessing for Movies 81 | #### raCategory - category that gets called for post-processing with Radarr 82 | [[movie]] 83 | enabled = 0 84 | apikey = 85 | host = localhost 86 | port = 7878 87 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 88 | web_root = 89 | ssl = 0 90 | # api key for www.omdbapi.com (used as alternative to imdb) 91 | omdbapikey = 92 | delete_failed = 0 93 | # Enable/Disable linking for Torrents 94 | Torrent_NoLink = 0 95 | keep_archive = 1 96 | extract = 1 97 | nzbExtractionBy = Downloader 98 | wait_for = 6 99 | # Set this to minimum required size to consider a media file valid (in MB) 100 | minSize = 0 101 | # Enable/Disable deleting ignored files (samples and invalid media files) 102 | delete_ignored = 0 103 | ##### Enable if NzbDrone is on a remote server for this category 104 | remote_path = 0 105 | ##### Set to path where download client places completed downloads locally for this category 106 | watch_dir = 107 | ##### Set to define import behavior Move or Copy 108 | importMode = Copy 109 | 110 | [SickBeard] 111 | #### autoProcessing for TV Series 112 | #### tv - category that gets called for post-processing with SB 113 | [[tv]] 114 | enabled = 0 115 | host = localhost 116 | port = 8081 117 | apikey = 118 | username = 119 | password = 120 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 121 | web_root = 122 | ssl = 0 123 | fork = auto 124 | delete_failed = 0 125 | # Enable/Disable linking for Torrents 126 | Torrent_NoLink = 0 127 | keep_archive = 1 128 | process_method = 129 | # force processing of already processed content when running a manual scan. 130 | force = 0 131 | # tell SickRage/Medusa to delete all source files after processing. 132 | delete_on = 0 133 | # tell Medusa to ignore check for associated subtitle check when postponing release 134 | ignore_subs = 0 135 | extract = 1 136 | nzbExtractionBy = Downloader 137 | # Set this to minimum required size to consider a media file valid (in MB) 138 | minSize = 0 139 | # Enable/Disable deleting ignored files (samples and invalid media files) 140 | delete_ignored = 0 141 | ##### Enable if SickBeard is on a remote server for this category 142 | remote_path = 0 143 | ##### Set to path where download client places completed downloads locally for this category 144 | watch_dir = 145 | ##### Set the recursive directory permissions to the following (0 to disable) 146 | chmodDirectory = 0 147 | 148 | [NzbDrone] 149 | #### Formerly known as NzbDrone this is now Sonarr 150 | #### autoProcessing for TV Series 151 | #### ndCategory - category that gets called for post-processing with NzbDrone/Sonarr 152 | [[sonarr]] 153 | enabled = 1 154 | apikey = {{ sonarr_api_key }} 155 | host = sonarr.local 156 | port = 8989 157 | username = 158 | password = 159 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 160 | web_root = /sonarr 161 | ssl = 0 162 | delete_failed = 0 163 | # Enable/Disable linking for Torrents 164 | Torrent_NoLink = 0 165 | keep_archive = 1 166 | extract = 1 167 | nzbExtractionBy = Downloader 168 | wait_for = 6 169 | # Set this to minimum required size to consider a media file valid (in MB) 170 | minSize = 0 171 | # Enable/Disable deleting ignored files (samples and invalid media files) 172 | delete_ignored = 0 173 | ##### Enable if NzbDrone is on a remote server for this category 174 | remote_path = 0 175 | ##### Set to path where download client places completed downloads locally for this category 176 | watch_dir = /mnt/downloads/bittorrent/sonarr 177 | ##### Set to define import behavior Move or Copy 178 | importMode = Copy 179 | [[radarr]] 180 | enabled = 1 181 | apikey = {{ radarr_api_key }} 182 | host = radarr.local 183 | port = 8989 184 | username = 185 | password = 186 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 187 | web_root = /radarr 188 | ssl = 0 189 | delete_failed = 0 190 | # Enable/Disable linking for Torrents 191 | Torrent_NoLink = 0 192 | keep_archive = 1 193 | extract = 1 194 | nzbExtractionBy = Downloader 195 | wait_for = 6 196 | # Set this to minimum required size to consider a media file valid (in MB) 197 | minSize = 0 198 | # Enable/Disable deleting ignored files (samples and invalid media files) 199 | delete_ignored = 0 200 | ##### Enable if NzbDrone is on a remote server for this category 201 | remote_path = 0 202 | ##### Set to path where download client places completed downloads locally for this category 203 | watch_dir = /mnt/downloads/bittorrent/radarr 204 | ##### Set to define import behavior Move or Copy 205 | importMode = Copy 206 | 207 | [HeadPhones] 208 | #### autoProcessing for Music 209 | #### music - category that gets called for post-processing with HP 210 | [[music]] 211 | enabled = 0 212 | apikey = 213 | host = localhost 214 | port = 8181 215 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 216 | ssl = 0 217 | web_root = 218 | delete_failed = 0 219 | wait_for = 2 220 | # Enable/Disable linking for Torrents 221 | Torrent_NoLink = 0 222 | keep_archive = 1 223 | extract = 1 224 | # Set this to minimum required size to consider a media file valid (in MB) 225 | minSize = 0 226 | # Enable/Disable deleting ignored files (samples and invalid media files) 227 | delete_ignored = 0 228 | ##### Enable if HeadPhones is on a remote server for this category 229 | remote_path = 0 230 | ##### Set to path where download client places completed downloads locally for this category 231 | watch_dir = 232 | 233 | [Lidarr] 234 | #### autoProcessing for Music 235 | #### LiCategory - category that gets called for post-processing with Lidarr 236 | [[music]] 237 | enabled = 0 238 | apikey = 239 | host = localhost 240 | port = 8686 241 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 242 | web_root = 243 | ssl = 0 244 | delete_failed = 0 245 | # Enable/Disable linking for Torrents 246 | Torrent_NoLink = 0 247 | keep_archive = 1 248 | extract = 1 249 | nzbExtractionBy = Downloader 250 | wait_for = 6 251 | # Set this to minimum required size to consider a media file valid (in MB) 252 | minSize = 0 253 | # Enable/Disable deleting ignored files (samples and invalid media files) 254 | delete_ignored = 0 255 | ##### Enable if NzbDrone is on a remote server for this category 256 | remote_path = 0 257 | ##### Set to path where download client places completed downloads locally for this category 258 | watch_dir = 259 | 260 | [Mylar] 261 | #### autoProcessing for Comics 262 | #### comics - category that gets called for post-processing with Mylar 263 | [[comics]] 264 | enabled = 0 265 | host = localhost 266 | port= 8090 267 | apikey= 268 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 269 | web_root= 270 | ssl=0 271 | # Enable/Disable linking for Torrents 272 | Torrent_NoLink = 0 273 | keep_archive = 1 274 | extract = 1 275 | # Set this to minimum required size to consider a media file valid (in MB) 276 | minSize = 0 277 | # Enable/Disable deleting ignored files (samples and invalid media files) 278 | delete_ignored = 0 279 | ##### Enable if Mylar is on a remote server for this category 280 | remote_path = 0 281 | ##### Set to path where download client places completed downloads locally for this category 282 | watch_dir = 283 | 284 | [Gamez] 285 | #### autoProcessing for Games 286 | #### games - category that gets called for post-processing with Gamez 287 | [[games]] 288 | enabled = 0 289 | apikey = 290 | host = localhost 291 | port = 8085 292 | ###### 293 | library = Set to path where you want the processed games to be moved to. 294 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 295 | ssl = 0 296 | web_root = 297 | # Enable/Disable linking for Torrents 298 | Torrent_NoLink = 0 299 | keep_archive = 1 300 | extract = 1 301 | # Set this to minimum required size to consider a media file valid (in MB) 302 | minSize = 0 303 | # Enable/Disable deleting ignored files (samples and invalid media files) 304 | delete_ignored = 0 305 | ##### Enable if Gamez is on a remote server for this category 306 | remote_path = 0 307 | ##### Set to path where download client places completed downloads locally for this category 308 | watch_dir = 309 | 310 | [Network] 311 | # Enter Mount points as LocalPath,RemotePath and separate each pair with '|' 312 | # e.g. MountPoints = /volume1/Public/,E:\|/volume2/share/,\\NAS\ 313 | mount_points = 314 | 315 | [Nzb] 316 | ###### clientAgent - Supported clients: sabnzbd, nzbget 317 | clientAgent = sabnzbd 318 | ###### SabNZBD (You must edit this if you're using nzbToMedia.py with SabNZBD) 319 | sabnzbd_host = http://localhost 320 | sabnzbd_port = 8080 321 | sabnzbd_apikey = 322 | ###### Enter the default path to your default download directory (non-category downloads). this directory is protected by safe_mode. 323 | default_downloadDirectory = 324 | 325 | [Torrent] 326 | ###### clientAgent - Supported clients: utorrent, transmission, deluge, rtorrent, vuze, qbittorrent, other 327 | clientAgent = rtorrent 328 | ###### useLink - Set to hard for physical links, sym for symbolic links, move to move, move-sym to move and link back, and no to not use links (copy) 329 | useLink = no 330 | ###### outputDirectory - Default output directory (categories will be appended as sub directory to outputDirectory) 331 | outputDirectory = /mnt/downloads/bittorrent 332 | ###### Enter the default path to your default download directory (non-category downloads). this directory is protected by safe_mode. 333 | default_downloadDirectory = 334 | ###### Other categories/labels defined for your downloader. Does not include CouchPotato, SickBeard, HeadPhones, Mylar categories. 335 | categories = sonarr 336 | ###### A list of categories that you don't want to be flattened (i.e preserve the directory structure when copying/linking. 337 | noFlatten = pictures,manual 338 | ###### uTorrent Hardlink solution (You must edit this if you're using TorrentToMedia.py with uTorrent) 339 | uTorrentWEBui = http://localhost:8090/gui/ 340 | uTorrentUSR = your username 341 | uTorrentPWD = your password 342 | ###### Transmission (You must edit this if you're using TorrentToMedia.py with Transmission) 343 | TransmissionHost = localhost 344 | TransmissionPort = 9091 345 | TransmissionUSR = your username 346 | TransmissionPWD = your password 347 | #### Deluge (You must edit this if you're using TorrentToMedia.py with deluge. Note that the host/port is for the deluge daemon, not the webui) 348 | DelugeHost = localhost 349 | DelugePort = 58846 350 | DelugeUSR = your username 351 | DelugePWD = your password 352 | ###### qBittorrent (You must edit this if you're using TorrentToMedia.py with qBittorrent) 353 | qBittorrenHost = localhost 354 | qBittorrentPort = 8080 355 | qBittorrentUSR = your username 356 | qBittorrentPWD = your password 357 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 358 | deleteOriginal = 0 359 | chmodDirectory = 0 360 | resume = 1 361 | resumeOnFailure = 1 362 | 363 | [Extensions] 364 | compressedExtensions = .zip,.rar,.7z,.gz,.bz,.tar,.arj,.1,.01,.001 365 | mediaExtensions = .mkv,.avi,.divx,.xvid,.mov,.wmv,.mp4,.mpg,.mpeg,.vob,.iso,.m4v,.ts 366 | audioExtensions = .mp3, .aac, .ogg, .ape, .m4a, .asf, .wma, .flac 367 | metaExtensions = .nfo,.sub,.srt,.jpg,.gif 368 | 369 | [Plex] 370 | # Only enter these details if you want to update plex library after processing. 371 | # Do not enter these details if you send the plex notifications from Sickbeard/CouchPotato. 372 | plex_host = localhost 373 | plex_port = 32400 374 | plex_token = 375 | plex_ssl = 0 376 | # Enter Plex category to section mapping as Category,section and separate each pair with '|' 377 | # e.g. plex_sections = movie,3|tv,4 378 | plex_sections = 379 | 380 | [Transcoder] 381 | # getsubs. enable to download subtitles. 382 | getSubs = 0 383 | # subLanguages. create a list of languages in the order you want them in your subtitles. 384 | subLanguages = eng,spa,fra 385 | # transcode. enable to use transcoder 386 | transcode = 0 387 | ###### duplicate =1 will create a new file. =0 will replace the original 388 | duplicate = 1 389 | # concat. joins cd1 cd2 etc into a single video. 390 | concat = 1 391 | # IgnoreExtensions is a comma-separated list of extensions that will not be transcoded. 392 | ignoreExtensions = .avi,.mkv,.mp4 393 | # outputFastStart. 1 will use -movflags + faststart. 0 will disable this from being used. 394 | outputFastStart = 0 395 | # outputQualityPercent. used as -q:a value. 0 will disable this from being used. 396 | outputQualityPercent = 0 397 | # outputVideoPath. Set path you want transcoded videos moved to. Leave blank to disable. 398 | outputVideoPath = 399 | # processOutput. 1 will send the outputVideoPath to SickBeard/CouchPotato. 0 will send original files. 400 | processOutput = 0 401 | # audioLanguage. set the 3 letter language code you want as your primary audio track. 402 | audioLanguage = eng 403 | # allAudioLanguages. 1 will keep all audio tracks (uses AudioCodec3) where available. 404 | allAudioLanguages = 0 405 | # allSubLanguages. 1 will keep all existing sub languages. 0 will discard those not in your list above. 406 | allSubLanguages = 0 407 | # embedSubs. 1 will embed external sub/srt subs into your video if this is supported. 408 | embedSubs = 1 409 | # burnInSubtitle. burns the default sub language into your video (needed for players that don't support subs) 410 | burnInSubtitle = 0 411 | # extractSubs. 1 will extract subs from the video file and save these as external srt files. 412 | extractSubs = 0 413 | # externalSubDir. set the directory where subs should be saved (if not the same directory as the video) 414 | externalSubDir = 415 | # hwAccel. 1 will set ffmpeg to enable hardware acceleration (this requires a recent ffmpeg) 416 | hwAccel = 0 417 | # generalOptions. Enter your additional ffmpeg options here with commas to separate each option/value (i.e replace spaces with commas). 418 | generalOptions = 419 | # outputDefault. Loads default configs for the selected device. The remaining options below are ignored. 420 | # If you want to use your own profile, leave this blank and set the remaining options below. 421 | # outputDefault profiles allowed: iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p, mkv, mp4-scene-release 422 | outputDefault = 423 | #### Define custom settings below. 424 | outputVideoExtension = .mp4 425 | outputVideoCodec = libx264 426 | VideoCodecAllow = 427 | outputVideoPreset = medium 428 | outputVideoResolution = 1920:1080 429 | outputVideoFramerate = 24 430 | outputVideoBitrate = 800000 431 | outputVideoCRF = 19 432 | outputVideoLevel = 3.1 433 | outputAudioCodec = ac3 434 | AudioCodecAllow = 435 | outputAudioChannels = 6 436 | outputAudioBitrate = 640k 437 | outputAudioTrack2Codec = libfaac 438 | AudioCodec2Allow = 439 | outputAudioTrack2Channels = 2 440 | outputAudioTrack2Bitrate = 128000 441 | outputAudioOtherCodec = libmp3lame 442 | AudioOtherCodecAllow = 443 | outputAudioOtherChannels = 444 | outputAudioOtherBitrate = 128000 445 | outputSubtitleCodec = 446 | 447 | [WakeOnLan] 448 | ###### set wake = 1 to send WOL broadcast to the mac and test the server (e.g. xbmc) the host and port specified. 449 | wake = 0 450 | host = 192.168.1.37 451 | port = 80 452 | mac = 00:01:2e:2D:64:e1 453 | 454 | [UserScript] 455 | #Use user_script for uncategorized downloads 456 | #Set the categories to use external script. 457 | #Use "UNCAT" to process non-category downloads, and "ALL" for all defined categories. 458 | [[UNCAT]] 459 | #Enable/Disable this subsection category 460 | enabled = 0 461 | Torrent_NoLink = 0 462 | keep_archive = 1 463 | extract = 1 464 | #Enable if you are sending commands to a remote server for this category 465 | remote_path = 0 466 | #What extension do you want to process? Specify all the extension, or use "ALL" to process all files. 467 | user_script_mediaExtensions = .mkv,.avi,.divx,.xvid,.mov,.wmv,.mp4,.mpg,.mpeg 468 | #Specify the path to your custom script. Use "None" if you wish to link this category, but NOT run any external script. 469 | user_script_path = /nzbToMedia/userscripts/script.sh 470 | #Specify the argument(s) passed to script, comma separated in order. 471 | #for example FP,FN,DN, TN, TL for file path (absolute file name with path), file name, absolute directory name (with path), Torrent Name, Torrent Label/Category. 472 | #So the result is /media/test/script/script.sh FP FN DN TN TL. Add other arguments as needed eg -f, -r 473 | user_script_param = FN 474 | #Set user_script_runOnce = 0 to run for each file, or 1 to only run once (presumably on the entire directory). 475 | user_script_runOnce = 0 476 | #Specify the successcodes returned by the user script as a comma separated list. Linux default is 0 477 | user_script_successCodes = 0 478 | #Clean after? Note that delay function is used to prevent possible mistake :) Delay is intended as seconds 479 | user_script_clean = 1 480 | delay = 120 481 | #Unique path (directory) created for every download. set 0 to disable. 482 | unique_path = 1 483 | ##### Set to path where download client places completed downloads locally for this category 484 | watch_dir = 485 | 486 | [ASCII] 487 | #Set convert =1 if you want to convert any "foreign" characters to ASCII (UTF8) before passing to SB/CP etc. Default is disabled (0). 488 | convert = 0 489 | 490 | [Passwords] 491 | # enter the full path to a text file containing passwords to be used for extraction attempts. 492 | # In the passwords file, every password should be on a new line 493 | PassWordFile = 494 | 495 | [Custom] 496 | # enter a list (comma separated) of Group Tags you want removed from filenames to help with subtitle matching. 497 | # e.g remove_group = [rarbag],-NZBgeek 498 | # be careful if your "group" is a common "real" word. Please report if you have any group replacements that would fall in this category. 499 | remove_group = 500 | -------------------------------------------------------------------------------- /roles/rtorrent/templates/rtorrent.rc: -------------------------------------------------------------------------------- 1 | scgi_local = ~/rpc.socket 2 | schedule = scgi_permission,0,0,"execute.nothrow=chmod,\"g+w,o=\",~/rpc.socket" 3 | session = ~/.rtorrent.session 4 | directory = /mnt/downloads/bittorrent/incomplete 5 | encryption = require,allow_incoming,require_RC4 6 | method.set_key = event.download.finished,TorrentToMedia,"execute=/usr/local/bin/python2,~/nzbtomedia/TorrentToMedia.py,$d.base_path=,$d.name=,$d.custom1=,$d.hash=" 7 | -------------------------------------------------------------------------------- /roles/rtorrent/templates/rtorrent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: rtorrent 4 | # REQUIRE: DAEMON cleanvar 5 | # KEYWORD: shutdown 6 | 7 | . /etc/rc.subr 8 | 9 | rtorrent_home=/usr/local/libdata/rtorrent 10 | rtorrent_bin=/usr/local/bin/rtorrent 11 | 12 | name=rtorrent 13 | rcvar=rtorrent_enable 14 | procname=${rtorrent_bin} 15 | command=/usr/local/bin/dtach 16 | dtach_dir="/var/run/rtorrent" 17 | command_args="-n ${dtach_dir}/rtorrent.dtach ${rtorrent_home}/set_home.sh ${rtorrent_bin}" 18 | rtorrent_chdir=${rtorrent_home} 19 | rtorrent_user=rtorrent 20 | argument_precmd= 21 | 22 | [ -d $dtach_dir ] || mkdir $dtach_dir 23 | chown $rtorrent_user $dtach_dir 24 | load_rc_config $name 25 | export PATH="$PATH:/usr/local/bin" 26 | run_rc_command "$@" 27 | -------------------------------------------------------------------------------- /roles/rtorrent/templates/set_home.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | export HOME=$(eval printf ~"$(whoami)") 3 | exec "$@" 4 | -------------------------------------------------------------------------------- /roles/rutorrent/files/labels/couchpotato.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andsens/freenas-jailconfig/60d09a7a4921ee6c132051b1f3568cee756a8a7d/roles/rutorrent/files/labels/couchpotato.png -------------------------------------------------------------------------------- /roles/rutorrent/files/labels/movies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andsens/freenas-jailconfig/60d09a7a4921ee6c132051b1f3568cee756a8a7d/roles/rutorrent/files/labels/movies.png -------------------------------------------------------------------------------- /roles/rutorrent/files/labels/sonarr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andsens/freenas-jailconfig/60d09a7a4921ee6c132051b1f3568cee756a8a7d/roles/rutorrent/files/labels/sonarr.png -------------------------------------------------------------------------------- /roles/rutorrent/meta/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | dependencies: 4 | - role: nginx 5 | - role: php 6 | -------------------------------------------------------------------------------- /roles/rutorrent/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install rutorrent dependencies 4 | pkgng: 5 | name: 6 | - ffmpeg 7 | - mediainfo 8 | - unrar 9 | - sox 10 | state: present 11 | 12 | - name: create rutorrent user 13 | user: 14 | name: rutorrent 15 | groups: 16 | - media 17 | - rtorrent 18 | state: present 19 | home: /usr/local/www/rutorrent 20 | createhome: no 21 | 22 | - name: add the www user to the rtorrent group 23 | user: 24 | name: www 25 | groups: rtorrent 26 | append: yes 27 | notify: restart nginx 28 | 29 | - name: create rutorrent webdir 30 | file: 31 | path: /usr/local/www/rutorrent 32 | state: directory 33 | owner: root 34 | group: wheel 35 | mode: 0755 36 | 37 | - name: clone rutorrent 38 | git: 39 | repo: https://github.com/Novik/ruTorrent.git 40 | dest: /usr/local/www/rutorrent 41 | version: 8ee59f7fc1b0a77b7048fc1f210d5539449d19f2 42 | update: yes 43 | force: yes 44 | register: rutorrent_cloned 45 | notify: restart php-fpm 46 | 47 | - name: clone rutorrent mobile plugin 48 | git: 49 | repo: https://github.com/xombiemp/rutorrentMobile.git 50 | dest: /usr/local/www/rutorrent/plugins/mobile 51 | version: 068099105acc7aca6fae94db34deecd9ce08122b 52 | update: yes 53 | register: rutorrent_mobile_cloned 54 | notify: restart php-fpm 55 | 56 | - name: set base permissions on rutorrent files 57 | file: 58 | path: /usr/local/www/rutorrent 59 | state: directory 60 | recurse: yes 61 | owner: root 62 | group: wheel 63 | mode: 'u=rwX,go=rX' 64 | when: rutorrent_cloned is changed or rutorrent_mobile_cloned is changed 65 | 66 | - name: change owner of share/ to rutorrent 67 | file: 68 | path: /usr/local/www/rutorrent/share 69 | state: directory 70 | recurse: yes 71 | owner: rutorrent 72 | group: wheel 73 | mode: 'u=rwX,go=rX' 74 | 75 | - name: copy labels to rutorrent tracklabels plugin 76 | copy: 77 | src: labels/ 78 | dest: /usr/local/www/rutorrent/plugins/tracklabels/labels 79 | owner: root 80 | group: wheel 81 | mode: 0644 82 | loop: 83 | - couchpotato.png 84 | - sonarr.png 85 | 86 | - name: configure rutorrent 87 | template: 88 | src: config.php 89 | dest: /usr/local/www/rutorrent/conf/config.php 90 | owner: root 91 | group: wheel 92 | mode: 0644 93 | tags: [config] 94 | 95 | - name: create php-fpm pool folder 96 | file: 97 | path: /usr/local/etc/fpm-pool.d 98 | state: directory 99 | owner: root 100 | group: wheel 101 | mode: 0755 102 | 103 | - name: enable php-fpm pool configs 104 | lineinfile: 105 | dest: /usr/local/etc/php-fpm.conf 106 | line: include=etc/fpm-pool.d/*.conf 107 | notify: restart php-fpm 108 | 109 | - name: create rutorrent php pool 110 | template: 111 | src: php-pool.conf 112 | dest: /usr/local/etc/fpm-pool.d/rutorrent.conf 113 | owner: root 114 | group: wheel 115 | mode: 0644 116 | notify: restart php-fpm 117 | tags: [config] 118 | 119 | - name: create the nginx vhost 120 | template: 121 | src: nginx-vhost.conf 122 | dest: /usr/local/etc/nginx/sites-available/rutorrent 123 | owner: root 124 | group: wheel 125 | mode: 0644 126 | notify: reload nginx 127 | tags: [config] 128 | 129 | - name: disable flood vhost 130 | file: 131 | path: /usr/local/etc/nginx/sites-enabled/flood 132 | state: absent 133 | notify: reload nginx 134 | 135 | - name: enable the vhost 136 | file: 137 | src: /usr/local/etc/nginx/sites-available/rutorrent 138 | dest: /usr/local/etc/nginx/sites-enabled/rutorrent 139 | state: link 140 | notify: reload nginx 141 | -------------------------------------------------------------------------------- /roles/rutorrent/templates/config.php: -------------------------------------------------------------------------------- 1 | rtorrent link through unix domain socket 34 | // (scgi_local in rtorrent conf file), change variables 35 | // above to something like this: 36 | // 37 | $scgi_port = 0; 38 | $scgi_host = "unix:///usr/local/libdata/rtorrent/rpc.socket"; 39 | 40 | $XMLRPCMountPoint = "/RPC2"; // DO NOT DELETE THIS LINE!!! DO NOT COMMENT THIS LINE!!! 41 | 42 | $pathToExternals = array( 43 | "php" => '/usr/local/bin/php', // Something like /usr/bin/php. If empty, will be found in PATH. 44 | "curl" => '/usr/local/bin/curl', // Something like /usr/bin/curl. If empty, will be found in PATH. 45 | "gzip" => '/usr/bin/gzip', // Something like /usr/bin/gzip. If empty, will be found in PATH. 46 | "id" => '/usr/bin/id', // Something like /usr/bin/id. If empty, will be found in PATH. 47 | "stat" => '/usr/bin/stat', // Something like /usr/bin/stat. If empty, will be found in PATH. 48 | 'mediainfo' => '/usr/local/bin/mediainfo', 49 | 'ffmpeg' => '/usr/local/bin/ffmpeg', 50 | 'unrar' => '/usr/local/bin/unrar', 51 | ); 52 | 53 | $localhosts = array( // list of local interfaces 54 | "127.0.0.1", 55 | "localhost", 56 | ); 57 | 58 | $profilePath = '../share'; // Path to user profiles 59 | $profileMask = 0777; // Mask for files and directory creation in user profiles. 60 | // Both Webserver and rtorrent users must have read-write access to it. 61 | // For example, if Webserver and rtorrent users are in the same group then the value may be 0770. 62 | 63 | $tempDirectory = null; // Temp directory. Absolute path with trail slash. If null, then autodetect will be used. 64 | 65 | $canUseXSendFile = true; // If true then use X-Sendfile feature if it exist 66 | 67 | $locale = "UTF8"; 68 | -------------------------------------------------------------------------------- /roles/rutorrent/templates/config.php.orig: -------------------------------------------------------------------------------- 1 | rtorrent link through unix domain socket 34 | // (scgi_local in rtorrent conf file), change variables 35 | // above to something like this: 36 | // 37 | // $scgi_port = 0; 38 | // $scgi_host = "unix:///tmp/rpc.socket"; 39 | 40 | $XMLRPCMountPoint = "/RPC2"; // DO NOT DELETE THIS LINE!!! DO NOT COMMENT THIS LINE!!! 41 | 42 | $pathToExternals = array( 43 | "php" => '', // Something like /usr/bin/php. If empty, will be found in PATH. 44 | "curl" => '', // Something like /usr/bin/curl. If empty, will be found in PATH. 45 | "gzip" => '', // Something like /usr/bin/gzip. If empty, will be found in PATH. 46 | "id" => '', // Something like /usr/bin/id. If empty, will be found in PATH. 47 | "stat" => '', // Something like /usr/bin/stat. If empty, will be found in PATH. 48 | ); 49 | 50 | $localhosts = array( // list of local interfaces 51 | "127.0.0.1", 52 | "localhost", 53 | ); 54 | 55 | $profilePath = '../share'; // Path to user profiles 56 | $profileMask = 0777; // Mask for files and directory creation in user profiles. 57 | // Both Webserver and rtorrent users must have read-write access to it. 58 | // For example, if Webserver and rtorrent users are in the same group then the value may be 0770. 59 | 60 | $tempDirectory = null; // Temp directory. Absolute path with trail slash. If null, then autodetect will be used. 61 | 62 | $canUseXSendFile = false; // If true then use X-Sendfile feature if it exist 63 | 64 | $locale = "UTF8"; 65 | -------------------------------------------------------------------------------- /roles/rutorrent/templates/nginx-vhost.conf: -------------------------------------------------------------------------------- 1 | upstream php5-fpm { 2 | server unix:/var/run/php-fpm.rutorrent.sock; 3 | } 4 | upstream rtorrent { 5 | server unix:/usr/local/libdata/rtorrent/rpc.socket; 6 | } 7 | server { 8 | listen 80; 9 | root /usr/local/www/rutorrent; 10 | location /rutorrent { 11 | rewrite ^/rutorrent(/.*)$ $1 last; 12 | } 13 | location /RPC2 { 14 | include scgi_params; 15 | scgi_param SCRIPT_NAME /RPC2; 16 | scgi_pass rtorrent; 17 | } 18 | location ~ ^(/php|/plugins).+\.php$ { 19 | include fastcgi_params; 20 | fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; 21 | fastcgi_pass php5-fpm; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /roles/rutorrent/templates/php-pool.conf: -------------------------------------------------------------------------------- 1 | [rutorrent] 2 | 3 | user = rutorrent 4 | group = rutorrent 5 | listen = /var/run/php-fpm.rutorrent.sock 6 | listen.owner = www 7 | listen.group = www 8 | listen.mode = 0660 9 | pm = dynamic 10 | pm.max_children = 5 11 | pm.start_servers = 1 12 | pm.min_spare_servers = 1 13 | pm.max_spare_servers = 2 14 | php_admin_value[error_log] = /var/log/php-fpm.rutorrent.log 15 | env[PATH] = /bin:/usr/bin:/usr/local/bin 16 | -------------------------------------------------------------------------------- /roles/sabnzbd/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start sabnzbd 4 | service: 5 | name: sabnzbd 6 | state: started 7 | 8 | - name: restart sabnzbd 9 | service: 10 | name: sabnzbd 11 | state: restarted 12 | -------------------------------------------------------------------------------- /roles/sabnzbd/meta/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | dependencies: 4 | - role: nginx 5 | -------------------------------------------------------------------------------- /roles/sabnzbd/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install sabnzbd 4 | pkgng: 5 | name: sabnzbdplus 6 | state: present 7 | 8 | - name: add the sabnzbd user to the media group 9 | user: 10 | name: _sabnzbd 11 | groups: media 12 | append: yes 13 | notify: restart nginx 14 | 15 | - name: add the www user to the sabnzbd group 16 | user: 17 | name: www 18 | groups: _sabnzbd 19 | append: yes 20 | notify: restart nginx 21 | 22 | - name: create sabnzbd script dir in home 23 | file: 24 | path: /usr/local/sabnzbd/scripts 25 | state: directory 26 | owner: _sabnzbd 27 | group: media 28 | mode: 0755 29 | 30 | - name: configure nzbtomedia 31 | include: nzbtomedia.yaml 32 | 33 | - name: create the nginx vhost 34 | template: 35 | src: nginx-vhost.conf 36 | dest: /usr/local/etc/nginx/sites-available/sabnzbd 37 | owner: root 38 | group: wheel 39 | mode: 0644 40 | notify: reload nginx 41 | tags: [config] 42 | 43 | - name: enable the vhost 44 | file: 45 | src: /usr/local/etc/nginx/sites-available/sabnzbd 46 | dest: /usr/local/etc/nginx/sites-enabled/sabnzbd 47 | state: link 48 | notify: reload nginx 49 | 50 | - name: enable sabnzbd 51 | service: 52 | name: sabnzbd 53 | enabled: yes 54 | notify: start sabnzbd 55 | -------------------------------------------------------------------------------- /roles/sabnzbd/tasks/nzbtomedia.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: alias python 2.7 to python 4 | file: 5 | src: python2.7 6 | dest: /usr/local/bin/python 7 | state: link 8 | 9 | - name: install nzbtomedia dependencies 10 | pkgng: 11 | name: 12 | - py27-sqlite3 13 | - ffmpeg 14 | - unrar 15 | - unzip 16 | - p7zip 17 | state: present 18 | 19 | - name: clone nzbtomedia 20 | git: 21 | repo: https://github.com/clinton-hall/nzbToMedia.git 22 | dest: /usr/local/sabnzbd/scripts/nzbtomedia 23 | version: 12.0.0 24 | update: no 25 | register: clone_nzbtomedia 26 | 27 | - name: set permissions on nzbtomedia files 28 | file: 29 | path: /usr/local/sabnzbd/scripts/nzbtomedia 30 | state: directory 31 | recurse: yes 32 | owner: _sabnzbd 33 | group: _sabnzbd 34 | mode: 'u=rwX,go=rX' 35 | when: clone_nzbtomedia is changed 36 | 37 | - name: configure nzbtomedia 38 | template: 39 | src: autoProcessMedia.cfg 40 | dest: /usr/local/sabnzbd/scripts/nzbtomedia/autoProcessMedia.cfg 41 | owner: _sabnzbd 42 | group: _sabnzbd 43 | mode: 0644 44 | tags: [config] 45 | -------------------------------------------------------------------------------- /roles/sabnzbd/templates/autoProcessMedia.cfg: -------------------------------------------------------------------------------- 1 | # nzbToMedia Configuration 2 | # For more information, visit https://github.com/clinton-hall/nzbToMedia/wiki 3 | 4 | [General] 5 | # Enable/Disable update notifications 6 | version_notify = 1 7 | # Enable/Disable automatic updates 8 | auto_update = 1 9 | # Set to the full path to the git executable 10 | git_path = /usr/local/bin/git 11 | # GitHUB user for repo 12 | git_user = 13 | # GitHUB branch for repo 14 | git_branch = 15 | # Enable/Disable forceful cleaning of leftover files following postprocess 16 | force_clean = 0 17 | # Enable/Disable logging debug messages to nzbtomedia.log 18 | log_debug = 0 19 | # Enable/Disable logging database messages to nzbtomedia.log 20 | log_db = 0 21 | # Enable/Disable logging environment variables to debug nzbtomedia.log (helpful to track down errors calling external tools.) 22 | log_env = 0 23 | # Enable/Disable logging git output to debug nzbtomedia.log (helpful to track down update failures.) 24 | log_git = 0 25 | # Set to the directory where your ffmpeg/ffprobe executables are located 26 | ffmpeg_path = /usr/local/bin 27 | # Enable/Disable media file checking using ffprobe. 28 | check_media = 1 29 | # Enable/Disable a safety check to ensure we don't process all downloads in the default_downloadDirectories by mistake. 30 | safe_mode = 1 31 | # Turn this on to disable additional extraction attempts for failed downloads. Default = 0 will attempt to extract and verify if media is present. 32 | no_extract_failed = 0 33 | 34 | [Posix] 35 | ### Process priority setting for External commands (Extractor and Transcoder) on Posix (Unix/Linux/OSX) systems. 36 | # Set the Niceness value for the nice command. These range from -20 (most favorable to the process) to 19 (least favorable to the process). 37 | niceness = 0 38 | # Set the ionice scheduling class. 0 for none, 1 for real time, 2 for best-effort, 3 for idle. 39 | ionice_class = 0 40 | # Set the ionice scheduling class data. This defines the class data, if the class accepts an argument. For real time and best-effort, 0-7 is valid data. 41 | ionice_classdata = 0 42 | 43 | [Windows] 44 | ### Set specific settings for Windows systems 45 | # Set this to 1 to allow extraction (7zip) windows to be lunched visble (for debugging) otherwise 0 to have this run in background. 46 | show_extraction = 0 47 | 48 | [CouchPotato] 49 | #### autoProcessing for Movies 50 | #### movie - category that gets called for post-processing with CPS 51 | [[movie]] 52 | enabled = 0 53 | apikey = 54 | host = localhost 55 | port = 5050 56 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 57 | ssl = 0 58 | web_root = 59 | # api key for www.omdbapi.com (used as alternative to imdb) 60 | omdbapikey = 61 | # Enable/Disable linking for Torrents 62 | Torrent_NoLink = 0 63 | keep_archive = 1 64 | method = renamer 65 | delete_failed = 0 66 | wait_for = 2 67 | extract = 1 68 | # Set this to minimum required size to consider a media file valid (in MB) 69 | minSize = 0 70 | # Enable/Disable deleting ignored files (samples and invalid media files) 71 | delete_ignored = 0 72 | ##### Enable if Couchpotato is on a remote server for this category 73 | remote_path = 0 74 | ##### Set to path where download client places completed downloads locally for this category 75 | watch_dir = 76 | ##### Set the recursive directory permissions to the following (0 to disable) 77 | chmodDirectory = 0 78 | 79 | [Radarr] 80 | #### autoProcessing for Movies 81 | #### raCategory - category that gets called for post-processing with Radarr 82 | [[movie]] 83 | enabled = 0 84 | apikey = 85 | host = localhost 86 | port = 7878 87 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 88 | web_root = 89 | ssl = 0 90 | # api key for www.omdbapi.com (used as alternative to imdb) 91 | omdbapikey = 92 | delete_failed = 0 93 | # Enable/Disable linking for Torrents 94 | Torrent_NoLink = 0 95 | keep_archive = 1 96 | extract = 1 97 | nzbExtractionBy = Downloader 98 | wait_for = 6 99 | # Set this to minimum required size to consider a media file valid (in MB) 100 | minSize = 0 101 | # Enable/Disable deleting ignored files (samples and invalid media files) 102 | delete_ignored = 0 103 | ##### Enable if NzbDrone is on a remote server for this category 104 | remote_path = 0 105 | ##### Set to path where download client places completed downloads locally for this category 106 | watch_dir = 107 | ##### Set to define import behavior Move or Copy 108 | importMode = Copy 109 | 110 | [SickBeard] 111 | #### autoProcessing for TV Series 112 | #### tv - category that gets called for post-processing with SB 113 | [[tv]] 114 | enabled = 0 115 | host = localhost 116 | port = 8081 117 | apikey = 118 | username = 119 | password = 120 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 121 | web_root = 122 | ssl = 0 123 | fork = auto 124 | delete_failed = 0 125 | # Enable/Disable linking for Torrents 126 | Torrent_NoLink = 0 127 | keep_archive = 1 128 | process_method = 129 | # force processing of already processed content when running a manual scan. 130 | force = 0 131 | # tell SickRage/Medusa to delete all source files after processing. 132 | delete_on = 0 133 | # tell Medusa to ignore check for associated subtitle check when postponing release 134 | ignore_subs = 0 135 | extract = 1 136 | nzbExtractionBy = Downloader 137 | # Set this to minimum required size to consider a media file valid (in MB) 138 | minSize = 0 139 | # Enable/Disable deleting ignored files (samples and invalid media files) 140 | delete_ignored = 0 141 | ##### Enable if SickBeard is on a remote server for this category 142 | remote_path = 0 143 | ##### Set to path where download client places completed downloads locally for this category 144 | watch_dir = 145 | ##### Set the recursive directory permissions to the following (0 to disable) 146 | chmodDirectory = 0 147 | 148 | [NzbDrone] 149 | #### Formerly known as NzbDrone this is now Sonarr 150 | #### autoProcessing for TV Series 151 | #### ndCategory - category that gets called for post-processing with NzbDrone/Sonarr 152 | [[tv]] 153 | enabled = 1 154 | apikey = 92346468b4c74bcf91ab1ff3bed84115 155 | host = sonarr.local 156 | port = 8989 157 | username = 158 | password = 159 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 160 | web_root = /sonarr 161 | ssl = 0 162 | delete_failed = 0 163 | # Enable/Disable linking for Torrents 164 | Torrent_NoLink = 0 165 | keep_archive = 1 166 | extract = 1 167 | nzbExtractionBy = Downloader 168 | wait_for = 6 169 | # Set this to minimum required size to consider a media file valid (in MB) 170 | minSize = 0 171 | # Enable/Disable deleting ignored files (samples and invalid media files) 172 | delete_ignored = 0 173 | ##### Enable if NzbDrone is on a remote server for this category 174 | remote_path = 0 175 | ##### Set to path where download client places completed downloads locally for this category 176 | watch_dir = /mnt/downloads/usenet/complete 177 | 178 | [HeadPhones] 179 | #### autoProcessing for Music 180 | #### music - category that gets called for post-processing with HP 181 | [[music]] 182 | enabled = 0 183 | apikey = 184 | host = localhost 185 | port = 8181 186 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 187 | ssl = 0 188 | web_root = 189 | delete_failed = 0 190 | wait_for = 2 191 | # Enable/Disable linking for Torrents 192 | Torrent_NoLink = 0 193 | keep_archive = 1 194 | extract = 1 195 | # Set this to minimum required size to consider a media file valid (in MB) 196 | minSize = 0 197 | # Enable/Disable deleting ignored files (samples and invalid media files) 198 | delete_ignored = 0 199 | ##### Enable if HeadPhones is on a remote server for this category 200 | remote_path = 0 201 | ##### Set to path where download client places completed downloads locally for this category 202 | watch_dir = 203 | 204 | [Lidarr] 205 | #### autoProcessing for Music 206 | #### LiCategory - category that gets called for post-processing with Lidarr 207 | [[music]] 208 | enabled = 0 209 | apikey = 210 | host = localhost 211 | port = 8686 212 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 213 | web_root = 214 | ssl = 0 215 | delete_failed = 0 216 | # Enable/Disable linking for Torrents 217 | Torrent_NoLink = 0 218 | keep_archive = 1 219 | extract = 1 220 | nzbExtractionBy = Downloader 221 | wait_for = 6 222 | # Set this to minimum required size to consider a media file valid (in MB) 223 | minSize = 0 224 | # Enable/Disable deleting ignored files (samples and invalid media files) 225 | delete_ignored = 0 226 | ##### Enable if NzbDrone is on a remote server for this category 227 | remote_path = 0 228 | ##### Set to path where download client places completed downloads locally for this category 229 | watch_dir = 230 | 231 | [Mylar] 232 | #### autoProcessing for Comics 233 | #### comics - category that gets called for post-processing with Mylar 234 | [[comics]] 235 | enabled = 0 236 | host = localhost 237 | port= 8090 238 | apikey= 239 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 240 | web_root= 241 | ssl=0 242 | # Enable/Disable linking for Torrents 243 | Torrent_NoLink = 0 244 | keep_archive = 1 245 | extract = 1 246 | # Set this to minimum required size to consider a media file valid (in MB) 247 | minSize = 0 248 | # Enable/Disable deleting ignored files (samples and invalid media files) 249 | delete_ignored = 0 250 | ##### Enable if Mylar is on a remote server for this category 251 | remote_path = 0 252 | ##### Set to path where download client places completed downloads locally for this category 253 | watch_dir = 254 | 255 | [Gamez] 256 | #### autoProcessing for Games 257 | #### games - category that gets called for post-processing with Gamez 258 | [[games]] 259 | enabled = 0 260 | apikey = 261 | host = localhost 262 | port = 8085 263 | ###### 264 | library = Set to path where you want the processed games to be moved to. 265 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 266 | ssl = 0 267 | web_root = 268 | # Enable/Disable linking for Torrents 269 | Torrent_NoLink = 0 270 | keep_archive = 1 271 | extract = 1 272 | # Set this to minimum required size to consider a media file valid (in MB) 273 | minSize = 0 274 | # Enable/Disable deleting ignored files (samples and invalid media files) 275 | delete_ignored = 0 276 | ##### Enable if Gamez is on a remote server for this category 277 | remote_path = 0 278 | ##### Set to path where download client places completed downloads locally for this category 279 | watch_dir = 280 | 281 | [Network] 282 | # Enter Mount points as LocalPath,RemotePath and separate each pair with '|' 283 | # e.g. MountPoints = /volume1/Public/,E:\|/volume2/share/,\\NAS\ 284 | mount_points = 285 | 286 | [Nzb] 287 | ###### clientAgent - Supported clients: sabnzbd, nzbget 288 | clientAgent = sabnzbd 289 | ###### SabNZBD (You must edit this if you're using nzbToMedia.py with SabNZBD) 290 | sabnzbd_host = http://localhost 291 | sabnzbd_port = 80 292 | sabnzbd_apikey = "8f9d92d2ccb8f51a08fe8910d54d5d53" 293 | ###### Enter the default path to your default download directory (non-category downloads). this directory is protected by safe_mode. 294 | default_downloadDirectory = 295 | 296 | [Torrent] 297 | ###### clientAgent - Supported clients: utorrent, transmission, deluge, rtorrent, vuze, qbittorrent, other 298 | clientAgent = other 299 | ###### useLink - Set to hard for physical links, sym for symbolic links, move to move, move-sym to move and link back, and no to not use links (copy) 300 | useLink = hard 301 | ###### outputDirectory - Default output directory (categories will be appended as sub directory to outputDirectory) 302 | outputDirectory = /abs/path/to/complete/ 303 | ###### Enter the default path to your default download directory (non-category downloads). this directory is protected by safe_mode. 304 | default_downloadDirectory = 305 | ###### Other categories/labels defined for your downloader. Does not include CouchPotato, SickBeard, HeadPhones, Mylar categories. 306 | categories = music_videos,pictures,software,manual 307 | ###### A list of categories that you don't want to be flattened (i.e preserve the directory structure when copying/linking. 308 | noFlatten = pictures,manual 309 | ###### uTorrent Hardlink solution (You must edit this if you're using TorrentToMedia.py with uTorrent) 310 | uTorrentWEBui = http://localhost:8090/gui/ 311 | uTorrentUSR = your username 312 | uTorrentPWD = your password 313 | ###### Transmission (You must edit this if you're using TorrentToMedia.py with Transmission) 314 | TransmissionHost = localhost 315 | TransmissionPort = 9091 316 | TransmissionUSR = your username 317 | TransmissionPWD = your password 318 | #### Deluge (You must edit this if you're using TorrentToMedia.py with deluge. Note that the host/port is for the deluge daemon, not the webui) 319 | DelugeHost = localhost 320 | DelugePort = 58846 321 | DelugeUSR = your username 322 | DelugePWD = your password 323 | ###### qBittorrent (You must edit this if you're using TorrentToMedia.py with qBittorrent) 324 | qBittorrenHost = localhost 325 | qBittorrentPort = 8080 326 | qBittorrentUSR = your username 327 | qBittorrentPWD = your password 328 | ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### 329 | deleteOriginal = 0 330 | chmodDirectory = 0 331 | resume = 1 332 | resumeOnFailure = 1 333 | 334 | [Extensions] 335 | compressedExtensions = .zip,.rar,.7z,.gz,.bz,.tar,.arj,.1,.01,.001 336 | mediaExtensions = .mkv,.avi,.divx,.xvid,.mov,.wmv,.mp4,.mpg,.mpeg,.vob,.iso,.m4v,.ts 337 | audioExtensions = .mp3, .aac, .ogg, .ape, .m4a, .asf, .wma, .flac 338 | metaExtensions = .nfo,.sub,.srt,.jpg,.gif 339 | 340 | [Plex] 341 | # Only enter these details if you want to update plex library after processing. 342 | # Do not enter these details if you send the plex notifications from Sickbeard/CouchPotato. 343 | plex_host = localhost 344 | plex_port = 32400 345 | plex_token = 346 | plex_ssl = 0 347 | # Enter Plex category to section mapping as Category,section and separate each pair with '|' 348 | # e.g. plex_sections = movie,3|tv,4 349 | plex_sections = 350 | 351 | [Transcoder] 352 | # getsubs. enable to download subtitles. 353 | getSubs = 0 354 | # subLanguages. create a list of languages in the order you want them in your subtitles. 355 | subLanguages = eng,spa,fra 356 | # transcode. enable to use transcoder 357 | transcode = 0 358 | ###### duplicate =1 will create a new file. =0 will replace the original 359 | duplicate = 1 360 | # concat. joins cd1 cd2 etc into a single video. 361 | concat = 1 362 | # IgnoreExtensions is a comma-separated list of extensions that will not be transcoded. 363 | ignoreExtensions = .avi,.mkv,.mp4 364 | # outputFastStart. 1 will use -movflags + faststart. 0 will disable this from being used. 365 | outputFastStart = 0 366 | # outputQualityPercent. used as -q:a value. 0 will disable this from being used. 367 | outputQualityPercent = 0 368 | # outputVideoPath. Set path you want transcoded videos moved to. Leave blank to disable. 369 | outputVideoPath = 370 | # processOutput. 1 will send the outputVideoPath to SickBeard/CouchPotato. 0 will send original files. 371 | processOutput = 0 372 | # audioLanguage. set the 3 letter language code you want as your primary audio track. 373 | audioLanguage = eng 374 | # allAudioLanguages. 1 will keep all audio tracks (uses AudioCodec3) where available. 375 | allAudioLanguages = 0 376 | # allSubLanguages. 1 will keep all existing sub languages. 0 will discard those not in your list above. 377 | allSubLanguages = 0 378 | # embedSubs. 1 will embed external sub/srt subs into your video if this is supported. 379 | embedSubs = 1 380 | # burnInSubtitle. burns the default sub language into your video (needed for players that don't support subs) 381 | burnInSubtitle = 0 382 | # extractSubs. 1 will extract subs from the video file and save these as external srt files. 383 | extractSubs = 0 384 | # externalSubDir. set the directory where subs should be saved (if not the same directory as the video) 385 | externalSubDir = 386 | # hwAccel. 1 will set ffmpeg to enable hardware acceleration (this requires a recent ffmpeg) 387 | hwAccel = 0 388 | # generalOptions. Enter your additional ffmpeg options here with commas to separate each option/value (i.e replace spaces with commas). 389 | generalOptions = 390 | # outputDefault. Loads default configs for the selected device. The remaining options below are ignored. 391 | # If you want to use your own profile, leave this blank and set the remaining options below. 392 | # outputDefault profiles allowed: iPad, iPad-1080p, iPad-720p, Apple-TV2, iPod, iPhone, PS3, xbox, Roku-1080p, Roku-720p, Roku-480p, mkv, mp4-scene-release 393 | outputDefault = 394 | #### Define custom settings below. 395 | outputVideoExtension = .mp4 396 | outputVideoCodec = libx264 397 | VideoCodecAllow = 398 | outputVideoPreset = medium 399 | outputVideoResolution = 1920:1080 400 | outputVideoFramerate = 24 401 | outputVideoBitrate = 800000 402 | outputVideoCRF = 19 403 | outputVideoLevel = 3.1 404 | outputAudioCodec = ac3 405 | AudioCodecAllow = 406 | outputAudioChannels = 6 407 | outputAudioBitrate = 640k 408 | outputAudioTrack2Codec = libfaac 409 | AudioCodec2Allow = 410 | outputAudioTrack2Channels = 2 411 | outputAudioTrack2Bitrate = 128000 412 | outputAudioOtherCodec = libmp3lame 413 | AudioOtherCodecAllow = 414 | outputAudioOtherChannels = 415 | outputAudioOtherBitrate = 128000 416 | outputSubtitleCodec = 417 | 418 | [WakeOnLan] 419 | ###### set wake = 1 to send WOL broadcast to the mac and test the server (e.g. xbmc) the host and port specified. 420 | wake = 0 421 | host = 192.168.1.37 422 | port = 80 423 | mac = 00:01:2e:2D:64:e1 424 | 425 | [UserScript] 426 | #Use user_script for uncategorized downloads 427 | #Set the categories to use external script. 428 | #Use "UNCAT" to process non-category downloads, and "ALL" for all defined categories. 429 | [[UNCAT]] 430 | #Enable/Disable this subsection category 431 | enabled = 0 432 | Torrent_NoLink = 0 433 | keep_archive = 1 434 | extract = 1 435 | #Enable if you are sending commands to a remote server for this category 436 | remote_path = 0 437 | #What extension do you want to process? Specify all the extension, or use "ALL" to process all files. 438 | user_script_mediaExtensions = .mkv,.avi,.divx,.xvid,.mov,.wmv,.mp4,.mpg,.mpeg 439 | #Specify the path to your custom script. Use "None" if you wish to link this category, but NOT run any external script. 440 | user_script_path = /nzbToMedia/userscripts/script.sh 441 | #Specify the argument(s) passed to script, comma separated in order. 442 | #for example FP,FN,DN, TN, TL for file path (absolute file name with path), file name, absolute directory name (with path), Torrent Name, Torrent Label/Category. 443 | #So the result is /media/test/script/script.sh FP FN DN TN TL. Add other arguments as needed eg -f, -r 444 | user_script_param = FN 445 | #Set user_script_runOnce = 0 to run for each file, or 1 to only run once (presumably on the entire directory). 446 | user_script_runOnce = 0 447 | #Specify the successcodes returned by the user script as a comma separated list. Linux default is 0 448 | user_script_successCodes = 0 449 | #Clean after? Note that delay function is used to prevent possible mistake :) Delay is intended as seconds 450 | user_script_clean = 1 451 | delay = 120 452 | #Unique path (directory) created for every download. set 0 to disable. 453 | unique_path = 1 454 | ##### Set to path where download client places completed downloads locally for this category 455 | watch_dir = 456 | 457 | [ASCII] 458 | #Set convert =1 if you want to convert any "foreign" characters to ASCII (UTF8) before passing to SB/CP etc. Default is disabled (0). 459 | convert = 0 460 | 461 | [Passwords] 462 | # enter the full path to a text file containing passwords to be used for extraction attempts. 463 | # In the passwords file, every password should be on a new line 464 | PassWordFile = 465 | 466 | [Custom] 467 | # enter a list (comma separated) of Group Tags you want removed from filenames to help with subtitle matching. 468 | # e.g remove_group = [rarbag],-NZBgeek 469 | # be careful if your "group" is a common "real" word. Please report if you have any group replacements that would fall in this category. 470 | remove_group = 471 | -------------------------------------------------------------------------------- /roles/sabnzbd/templates/nginx-vhost.conf: -------------------------------------------------------------------------------- 1 | upstream sabnzbd { 2 | server localhost:8080; 3 | } 4 | server { 5 | listen 80; 6 | location / { 7 | client_max_body_size 10m; 8 | 9 | proxy_set_header Host $host; 10 | proxy_set_header X-Real-IP $remote_addr; 11 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 12 | proxy_http_version 1.1; 13 | proxy_set_header Connection ""; 14 | 15 | proxy_pass http://sabnzbd; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /roles/sonarr/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start sonarr 4 | service: 5 | name: sonarr 6 | state: started 7 | 8 | - name: restart sonarr 9 | service: 10 | name: sonarr 11 | state: restarted 12 | -------------------------------------------------------------------------------- /roles/sonarr/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install sonarr 4 | pkgng: 5 | name: sonarr 6 | state: present 7 | 8 | - name: add the sonarr user to the media group 9 | user: 10 | name: sonarr 11 | groups: media 12 | append: yes 13 | notify: restart sonarr 14 | 15 | - name: allow sonarr to auto-update 16 | file: 17 | path: /usr/local/share/sonarr 18 | state: directory 19 | recurse: yes 20 | owner: sonarr 21 | group: wheel 22 | mode: 'u=rwX,go=rX' 23 | 24 | - name: enable sonarr 25 | service: 26 | name: sonarr 27 | enabled: yes 28 | notify: start sonarr 29 | -------------------------------------------------------------------------------- /roles/stats/HDD stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_TELEGRAF", 5 | "label": "telegraf", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "influxdb", 9 | "pluginName": "InfluxDB" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "4.6.2" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "" 24 | }, 25 | { 26 | "type": "datasource", 27 | "id": "influxdb", 28 | "name": "InfluxDB", 29 | "version": "1.0.0" 30 | }, 31 | { 32 | "type": "panel", 33 | "id": "table", 34 | "name": "Table", 35 | "version": "" 36 | } 37 | ], 38 | "annotations": { 39 | "list": [ 40 | { 41 | "builtIn": 1, 42 | "datasource": "-- Grafana --", 43 | "enable": true, 44 | "hide": true, 45 | "iconColor": "rgba(0, 211, 255, 1)", 46 | "name": "Annotations & Alerts", 47 | "type": "dashboard" 48 | } 49 | ] 50 | }, 51 | "editable": true, 52 | "gnetId": null, 53 | "graphTooltip": 0, 54 | "hideControls": false, 55 | "id": null, 56 | "links": [], 57 | "rows": [ 58 | { 59 | "collapse": false, 60 | "height": "250px", 61 | "panels": [ 62 | { 63 | "aliasColors": {}, 64 | "bars": false, 65 | "dashLength": 10, 66 | "dashes": false, 67 | "datasource": "${DS_TELEGRAF}", 68 | "fill": 0, 69 | "id": 1, 70 | "legend": { 71 | "avg": false, 72 | "current": false, 73 | "max": false, 74 | "min": false, 75 | "show": true, 76 | "total": false, 77 | "values": false 78 | }, 79 | "lines": true, 80 | "linewidth": 1, 81 | "links": [], 82 | "nullPointMode": "null", 83 | "percentage": false, 84 | "pointradius": 5, 85 | "points": false, 86 | "renderer": "flot", 87 | "seriesOverrides": [], 88 | "spaceLength": 10, 89 | "span": 6, 90 | "stack": false, 91 | "steppedLine": false, 92 | "targets": [ 93 | { 94 | "alias": "$tag_device", 95 | "dsType": "influxdb", 96 | "groupBy": [ 97 | { 98 | "params": [ 99 | "$__interval" 100 | ], 101 | "type": "time" 102 | }, 103 | { 104 | "params": [ 105 | "device" 106 | ], 107 | "type": "tag" 108 | }, 109 | { 110 | "params": [ 111 | "null" 112 | ], 113 | "type": "fill" 114 | } 115 | ], 116 | "measurement": "smart_attribute", 117 | "orderByTime": "ASC", 118 | "policy": "default", 119 | "refId": "A", 120 | "resultFormat": "time_series", 121 | "select": [ 122 | [ 123 | { 124 | "params": [ 125 | "raw_value" 126 | ], 127 | "type": "field" 128 | }, 129 | { 130 | "params": [], 131 | "type": "mean" 132 | } 133 | ] 134 | ], 135 | "tags": [ 136 | { 137 | "key": "name", 138 | "operator": "=", 139 | "value": "Temperature_Celsius" 140 | } 141 | ] 142 | } 143 | ], 144 | "thresholds": [], 145 | "timeFrom": null, 146 | "timeShift": null, 147 | "title": "Temperatures", 148 | "tooltip": { 149 | "shared": true, 150 | "sort": 0, 151 | "value_type": "individual" 152 | }, 153 | "type": "graph", 154 | "xaxis": { 155 | "buckets": null, 156 | "mode": "time", 157 | "name": null, 158 | "show": true, 159 | "values": [] 160 | }, 161 | "yaxes": [ 162 | { 163 | "format": "celsius", 164 | "label": null, 165 | "logBase": 1, 166 | "max": null, 167 | "min": null, 168 | "show": true 169 | }, 170 | { 171 | "format": "short", 172 | "label": null, 173 | "logBase": 1, 174 | "max": null, 175 | "min": null, 176 | "show": true 177 | } 178 | ] 179 | }, 180 | { 181 | "aliasColors": {}, 182 | "bars": false, 183 | "dashLength": 10, 184 | "dashes": false, 185 | "datasource": "${DS_TELEGRAF}", 186 | "fill": 1, 187 | "id": 6, 188 | "legend": { 189 | "alignAsTable": true, 190 | "avg": false, 191 | "current": false, 192 | "max": false, 193 | "min": false, 194 | "rightSide": true, 195 | "show": true, 196 | "total": false, 197 | "values": false 198 | }, 199 | "lines": true, 200 | "linewidth": 1, 201 | "links": [], 202 | "nullPointMode": "null", 203 | "percentage": false, 204 | "pointradius": 5, 205 | "points": false, 206 | "renderer": "flot", 207 | "seriesOverrides": [], 208 | "spaceLength": 10, 209 | "span": 6, 210 | "stack": false, 211 | "steppedLine": false, 212 | "targets": [ 213 | { 214 | "alias": "$tag_device $tag_name", 215 | "dsType": "influxdb", 216 | "groupBy": [ 217 | { 218 | "params": [ 219 | "$__interval" 220 | ], 221 | "type": "time" 222 | }, 223 | { 224 | "params": [ 225 | "device" 226 | ], 227 | "type": "tag" 228 | }, 229 | { 230 | "params": [ 231 | "name" 232 | ], 233 | "type": "tag" 234 | }, 235 | { 236 | "params": [ 237 | "null" 238 | ], 239 | "type": "fill" 240 | } 241 | ], 242 | "measurement": "smart_attribute", 243 | "orderByTime": "ASC", 244 | "policy": "default", 245 | "refId": "A", 246 | "resultFormat": "time_series", 247 | "select": [ 248 | [ 249 | { 250 | "params": [ 251 | "raw_value" 252 | ], 253 | "type": "field" 254 | }, 255 | { 256 | "params": [], 257 | "type": "mean" 258 | } 259 | ] 260 | ], 261 | "tags": [ 262 | { 263 | "key": "device", 264 | "operator": "!=", 265 | "value": "ada0" 266 | }, 267 | { 268 | "condition": "AND", 269 | "key": "name", 270 | "operator": "!=", 271 | "value": "Load_Cycle_Count" 272 | }, 273 | { 274 | "condition": "AND", 275 | "key": "name", 276 | "operator": "!=", 277 | "value": "Power_On_Hours" 278 | }, 279 | { 280 | "condition": "AND", 281 | "key": "name", 282 | "operator": "!=", 283 | "value": "Spin_Up_Time" 284 | }, 285 | { 286 | "condition": "AND", 287 | "key": "name", 288 | "operator": "!=", 289 | "value": "Temperature_Celsius" 290 | }, 291 | { 292 | "condition": "AND", 293 | "key": "name", 294 | "operator": "!=", 295 | "value": "Throughput_Performance" 296 | }, 297 | { 298 | "condition": "AND", 299 | "key": "name", 300 | "operator": "!=", 301 | "value": "Power-Off_Retract_Count" 302 | }, 303 | { 304 | "condition": "AND", 305 | "key": "name", 306 | "operator": "!=", 307 | "value": "Power_Cycle_Count" 308 | }, 309 | { 310 | "condition": "AND", 311 | "key": "name", 312 | "operator": "!=", 313 | "value": "Seek_Time_Performance" 314 | }, 315 | { 316 | "condition": "AND", 317 | "key": "name", 318 | "operator": "!=", 319 | "value": "Start_Stop_Count" 320 | }, 321 | { 322 | "condition": "AND", 323 | "key": "name", 324 | "operator": "!=", 325 | "value": "Perc_Avail_Resrvd_Space" 326 | } 327 | ] 328 | } 329 | ], 330 | "thresholds": [], 331 | "timeFrom": null, 332 | "timeShift": null, 333 | "title": "Everything else", 334 | "tooltip": { 335 | "shared": true, 336 | "sort": 0, 337 | "value_type": "individual" 338 | }, 339 | "type": "graph", 340 | "xaxis": { 341 | "buckets": null, 342 | "mode": "time", 343 | "name": null, 344 | "show": true, 345 | "values": [] 346 | }, 347 | "yaxes": [ 348 | { 349 | "format": "short", 350 | "label": null, 351 | "logBase": 1, 352 | "max": null, 353 | "min": null, 354 | "show": true 355 | }, 356 | { 357 | "format": "short", 358 | "label": null, 359 | "logBase": 1, 360 | "max": null, 361 | "min": null, 362 | "show": true 363 | } 364 | ] 365 | }, 366 | { 367 | "aliasColors": {}, 368 | "bars": false, 369 | "dashLength": 10, 370 | "dashes": false, 371 | "datasource": "${DS_TELEGRAF}", 372 | "fill": 0, 373 | "id": 5, 374 | "legend": { 375 | "avg": false, 376 | "current": false, 377 | "max": false, 378 | "min": false, 379 | "show": true, 380 | "total": false, 381 | "values": false 382 | }, 383 | "lines": true, 384 | "linewidth": 1, 385 | "links": [], 386 | "nullPointMode": "null", 387 | "percentage": false, 388 | "pointradius": 5, 389 | "points": false, 390 | "renderer": "flot", 391 | "seriesOverrides": [], 392 | "spaceLength": 10, 393 | "span": 4, 394 | "stack": false, 395 | "steppedLine": false, 396 | "targets": [ 397 | { 398 | "alias": "$tag_device", 399 | "dsType": "influxdb", 400 | "groupBy": [ 401 | { 402 | "params": [ 403 | "$__interval" 404 | ], 405 | "type": "time" 406 | }, 407 | { 408 | "params": [ 409 | "device" 410 | ], 411 | "type": "tag" 412 | }, 413 | { 414 | "params": [ 415 | "null" 416 | ], 417 | "type": "fill" 418 | } 419 | ], 420 | "measurement": "smart_attribute", 421 | "orderByTime": "ASC", 422 | "policy": "default", 423 | "refId": "A", 424 | "resultFormat": "time_series", 425 | "select": [ 426 | [ 427 | { 428 | "params": [ 429 | "raw_value" 430 | ], 431 | "type": "field" 432 | }, 433 | { 434 | "params": [], 435 | "type": "mean" 436 | } 437 | ] 438 | ], 439 | "tags": [ 440 | { 441 | "key": "name", 442 | "operator": "=", 443 | "value": "Spin_Up_Time" 444 | } 445 | ] 446 | } 447 | ], 448 | "thresholds": [], 449 | "timeFrom": null, 450 | "timeShift": null, 451 | "title": "Spin-up time", 452 | "tooltip": { 453 | "shared": true, 454 | "sort": 0, 455 | "value_type": "individual" 456 | }, 457 | "type": "graph", 458 | "xaxis": { 459 | "buckets": null, 460 | "mode": "time", 461 | "name": null, 462 | "show": true, 463 | "values": [] 464 | }, 465 | "yaxes": [ 466 | { 467 | "format": "ms", 468 | "label": null, 469 | "logBase": 1, 470 | "max": null, 471 | "min": "0", 472 | "show": true 473 | }, 474 | { 475 | "format": "short", 476 | "label": null, 477 | "logBase": 1, 478 | "max": null, 479 | "min": null, 480 | "show": true 481 | } 482 | ] 483 | }, 484 | { 485 | "aliasColors": {}, 486 | "bars": false, 487 | "dashLength": 10, 488 | "dashes": false, 489 | "datasource": "${DS_TELEGRAF}", 490 | "fill": 0, 491 | "id": 7, 492 | "legend": { 493 | "avg": false, 494 | "current": false, 495 | "max": false, 496 | "min": false, 497 | "show": true, 498 | "total": false, 499 | "values": false 500 | }, 501 | "lines": true, 502 | "linewidth": 1, 503 | "links": [], 504 | "nullPointMode": "null", 505 | "percentage": false, 506 | "pointradius": 5, 507 | "points": false, 508 | "renderer": "flot", 509 | "seriesOverrides": [], 510 | "spaceLength": 10, 511 | "span": 4, 512 | "stack": false, 513 | "steppedLine": false, 514 | "targets": [ 515 | { 516 | "alias": "$tag_device", 517 | "dsType": "influxdb", 518 | "groupBy": [ 519 | { 520 | "params": [ 521 | "$__interval" 522 | ], 523 | "type": "time" 524 | }, 525 | { 526 | "params": [ 527 | "device" 528 | ], 529 | "type": "tag" 530 | }, 531 | { 532 | "params": [ 533 | "null" 534 | ], 535 | "type": "fill" 536 | } 537 | ], 538 | "measurement": "smart_attribute", 539 | "orderByTime": "ASC", 540 | "policy": "default", 541 | "refId": "A", 542 | "resultFormat": "time_series", 543 | "select": [ 544 | [ 545 | { 546 | "params": [ 547 | "raw_value" 548 | ], 549 | "type": "field" 550 | }, 551 | { 552 | "params": [], 553 | "type": "mean" 554 | } 555 | ] 556 | ], 557 | "tags": [ 558 | { 559 | "key": "name", 560 | "operator": "=", 561 | "value": "Throughput_Performance" 562 | } 563 | ] 564 | } 565 | ], 566 | "thresholds": [], 567 | "timeFrom": null, 568 | "timeShift": null, 569 | "title": "Throughput performance", 570 | "tooltip": { 571 | "shared": true, 572 | "sort": 0, 573 | "value_type": "individual" 574 | }, 575 | "type": "graph", 576 | "xaxis": { 577 | "buckets": null, 578 | "mode": "time", 579 | "name": null, 580 | "show": true, 581 | "values": [] 582 | }, 583 | "yaxes": [ 584 | { 585 | "format": "short", 586 | "label": null, 587 | "logBase": 1, 588 | "max": null, 589 | "min": "0", 590 | "show": true 591 | }, 592 | { 593 | "format": "short", 594 | "label": null, 595 | "logBase": 1, 596 | "max": null, 597 | "min": null, 598 | "show": true 599 | } 600 | ] 601 | }, 602 | { 603 | "aliasColors": {}, 604 | "bars": false, 605 | "dashLength": 10, 606 | "dashes": false, 607 | "datasource": "${DS_TELEGRAF}", 608 | "fill": 0, 609 | "id": 9, 610 | "legend": { 611 | "avg": false, 612 | "current": false, 613 | "max": false, 614 | "min": false, 615 | "show": true, 616 | "total": false, 617 | "values": false 618 | }, 619 | "lines": true, 620 | "linewidth": 1, 621 | "links": [], 622 | "nullPointMode": "null", 623 | "percentage": false, 624 | "pointradius": 5, 625 | "points": false, 626 | "renderer": "flot", 627 | "seriesOverrides": [], 628 | "spaceLength": 10, 629 | "span": 4, 630 | "stack": false, 631 | "steppedLine": false, 632 | "targets": [ 633 | { 634 | "alias": "$tag_device", 635 | "dsType": "influxdb", 636 | "groupBy": [ 637 | { 638 | "params": [ 639 | "$__interval" 640 | ], 641 | "type": "time" 642 | }, 643 | { 644 | "params": [ 645 | "device" 646 | ], 647 | "type": "tag" 648 | }, 649 | { 650 | "params": [ 651 | "null" 652 | ], 653 | "type": "fill" 654 | } 655 | ], 656 | "measurement": "smart_attribute", 657 | "orderByTime": "ASC", 658 | "policy": "default", 659 | "refId": "A", 660 | "resultFormat": "time_series", 661 | "select": [ 662 | [ 663 | { 664 | "params": [ 665 | "raw_value" 666 | ], 667 | "type": "field" 668 | }, 669 | { 670 | "params": [], 671 | "type": "mean" 672 | } 673 | ] 674 | ], 675 | "tags": [ 676 | { 677 | "key": "name", 678 | "operator": "=", 679 | "value": "Seek_Time_Performance" 680 | } 681 | ] 682 | } 683 | ], 684 | "thresholds": [], 685 | "timeFrom": null, 686 | "timeShift": null, 687 | "title": "Seek time performance", 688 | "tooltip": { 689 | "shared": true, 690 | "sort": 0, 691 | "value_type": "individual" 692 | }, 693 | "type": "graph", 694 | "xaxis": { 695 | "buckets": null, 696 | "mode": "time", 697 | "name": null, 698 | "show": true, 699 | "values": [] 700 | }, 701 | "yaxes": [ 702 | { 703 | "format": "ms", 704 | "label": null, 705 | "logBase": 1, 706 | "max": null, 707 | "min": "0", 708 | "show": true 709 | }, 710 | { 711 | "format": "short", 712 | "label": null, 713 | "logBase": 1, 714 | "max": null, 715 | "min": null, 716 | "show": true 717 | } 718 | ] 719 | }, 720 | { 721 | "columns": [ 722 | { 723 | "text": "Avg", 724 | "value": "avg" 725 | } 726 | ], 727 | "datasource": "${DS_TELEGRAF}", 728 | "fontSize": "100%", 729 | "id": 12, 730 | "links": [], 731 | "pageSize": 5, 732 | "scroll": false, 733 | "showHeader": true, 734 | "sort": { 735 | "col": 0, 736 | "desc": false 737 | }, 738 | "span": 2, 739 | "styles": [ 740 | { 741 | "alias": "Time", 742 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 743 | "pattern": "Time", 744 | "type": "date" 745 | }, 746 | { 747 | "alias": "", 748 | "colorMode": null, 749 | "colors": [ 750 | "rgba(245, 54, 54, 0.9)", 751 | "rgba(237, 129, 40, 0.89)", 752 | "rgba(50, 172, 45, 0.97)" 753 | ], 754 | "decimals": 2, 755 | "pattern": "/.*/", 756 | "thresholds": [], 757 | "type": "number", 758 | "unit": "h" 759 | } 760 | ], 761 | "targets": [ 762 | { 763 | "alias": "$tag_device", 764 | "dsType": "influxdb", 765 | "groupBy": [ 766 | { 767 | "params": [ 768 | "$__interval" 769 | ], 770 | "type": "time" 771 | }, 772 | { 773 | "params": [ 774 | "device" 775 | ], 776 | "type": "tag" 777 | }, 778 | { 779 | "params": [ 780 | "null" 781 | ], 782 | "type": "fill" 783 | } 784 | ], 785 | "limit": "", 786 | "measurement": "smart_attribute", 787 | "orderByTime": "ASC", 788 | "policy": "default", 789 | "refId": "A", 790 | "resultFormat": "time_series", 791 | "select": [ 792 | [ 793 | { 794 | "params": [ 795 | "raw_value" 796 | ], 797 | "type": "field" 798 | }, 799 | { 800 | "params": [], 801 | "type": "last" 802 | } 803 | ] 804 | ], 805 | "slimit": "", 806 | "tags": [ 807 | { 808 | "key": "name", 809 | "operator": "=", 810 | "value": "Power_On_Hours" 811 | } 812 | ] 813 | } 814 | ], 815 | "title": "Time spent powered on", 816 | "transform": "timeseries_aggregations", 817 | "type": "table" 818 | }, 819 | { 820 | "columns": [ 821 | { 822 | "text": "Avg", 823 | "value": "avg" 824 | } 825 | ], 826 | "datasource": "${DS_TELEGRAF}", 827 | "fontSize": "100%", 828 | "id": 15, 829 | "links": [], 830 | "pageSize": 5, 831 | "scroll": false, 832 | "showHeader": true, 833 | "sort": { 834 | "col": 0, 835 | "desc": false 836 | }, 837 | "span": 2, 838 | "styles": [ 839 | { 840 | "alias": "Time", 841 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 842 | "pattern": "Time", 843 | "type": "date" 844 | }, 845 | { 846 | "alias": "", 847 | "colorMode": null, 848 | "colors": [ 849 | "rgba(245, 54, 54, 0.9)", 850 | "rgba(237, 129, 40, 0.89)", 851 | "rgba(50, 172, 45, 0.97)" 852 | ], 853 | "decimals": 0, 854 | "pattern": "/.*/", 855 | "thresholds": [], 856 | "type": "number", 857 | "unit": "short" 858 | } 859 | ], 860 | "targets": [ 861 | { 862 | "alias": "$tag_device", 863 | "dsType": "influxdb", 864 | "groupBy": [ 865 | { 866 | "params": [ 867 | "$__interval" 868 | ], 869 | "type": "time" 870 | }, 871 | { 872 | "params": [ 873 | "device" 874 | ], 875 | "type": "tag" 876 | }, 877 | { 878 | "params": [ 879 | "null" 880 | ], 881 | "type": "fill" 882 | } 883 | ], 884 | "limit": "", 885 | "measurement": "smart_attribute", 886 | "orderByTime": "ASC", 887 | "policy": "default", 888 | "refId": "A", 889 | "resultFormat": "time_series", 890 | "select": [ 891 | [ 892 | { 893 | "params": [ 894 | "raw_value" 895 | ], 896 | "type": "field" 897 | }, 898 | { 899 | "params": [], 900 | "type": "last" 901 | } 902 | ] 903 | ], 904 | "slimit": "", 905 | "tags": [ 906 | { 907 | "key": "name", 908 | "operator": "=", 909 | "value": "Power-Off_Retract_Count" 910 | } 911 | ] 912 | } 913 | ], 914 | "title": "Power off retract count", 915 | "transform": "timeseries_aggregations", 916 | "type": "table" 917 | }, 918 | { 919 | "columns": [ 920 | { 921 | "text": "Avg", 922 | "value": "avg" 923 | } 924 | ], 925 | "datasource": "${DS_TELEGRAF}", 926 | "fontSize": "100%", 927 | "id": 17, 928 | "links": [], 929 | "pageSize": 5, 930 | "scroll": false, 931 | "showHeader": true, 932 | "sort": { 933 | "col": 0, 934 | "desc": false 935 | }, 936 | "span": 2, 937 | "styles": [ 938 | { 939 | "alias": "Time", 940 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 941 | "pattern": "Time", 942 | "type": "date" 943 | }, 944 | { 945 | "alias": "", 946 | "colorMode": null, 947 | "colors": [ 948 | "rgba(245, 54, 54, 0.9)", 949 | "rgba(237, 129, 40, 0.89)", 950 | "rgba(50, 172, 45, 0.97)" 951 | ], 952 | "decimals": 0, 953 | "pattern": "/.*/", 954 | "thresholds": [], 955 | "type": "number", 956 | "unit": "none" 957 | } 958 | ], 959 | "targets": [ 960 | { 961 | "alias": "$tag_device", 962 | "dsType": "influxdb", 963 | "groupBy": [ 964 | { 965 | "params": [ 966 | "$__interval" 967 | ], 968 | "type": "time" 969 | }, 970 | { 971 | "params": [ 972 | "device" 973 | ], 974 | "type": "tag" 975 | }, 976 | { 977 | "params": [ 978 | "null" 979 | ], 980 | "type": "fill" 981 | } 982 | ], 983 | "limit": "", 984 | "measurement": "smart_attribute", 985 | "orderByTime": "ASC", 986 | "policy": "default", 987 | "refId": "A", 988 | "resultFormat": "time_series", 989 | "select": [ 990 | [ 991 | { 992 | "params": [ 993 | "raw_value" 994 | ], 995 | "type": "field" 996 | }, 997 | { 998 | "params": [], 999 | "type": "last" 1000 | } 1001 | ] 1002 | ], 1003 | "slimit": "", 1004 | "tags": [ 1005 | { 1006 | "key": "name", 1007 | "operator": "=", 1008 | "value": "Load_Cycle_Count" 1009 | } 1010 | ] 1011 | } 1012 | ], 1013 | "title": "Load cycle count", 1014 | "transform": "timeseries_aggregations", 1015 | "type": "table" 1016 | }, 1017 | { 1018 | "columns": [ 1019 | { 1020 | "text": "Avg", 1021 | "value": "avg" 1022 | } 1023 | ], 1024 | "datasource": "${DS_TELEGRAF}", 1025 | "fontSize": "100%", 1026 | "id": 14, 1027 | "links": [], 1028 | "pageSize": 5, 1029 | "scroll": false, 1030 | "showHeader": true, 1031 | "sort": { 1032 | "col": 0, 1033 | "desc": false 1034 | }, 1035 | "span": 2, 1036 | "styles": [ 1037 | { 1038 | "alias": "Time", 1039 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1040 | "pattern": "Time", 1041 | "type": "date" 1042 | }, 1043 | { 1044 | "alias": "", 1045 | "colorMode": null, 1046 | "colors": [ 1047 | "rgba(245, 54, 54, 0.9)", 1048 | "rgba(237, 129, 40, 0.89)", 1049 | "rgba(50, 172, 45, 0.97)" 1050 | ], 1051 | "decimals": 0, 1052 | "pattern": "/.*/", 1053 | "thresholds": [], 1054 | "type": "number", 1055 | "unit": "short" 1056 | } 1057 | ], 1058 | "targets": [ 1059 | { 1060 | "alias": "$tag_device", 1061 | "dsType": "influxdb", 1062 | "groupBy": [ 1063 | { 1064 | "params": [ 1065 | "$__interval" 1066 | ], 1067 | "type": "time" 1068 | }, 1069 | { 1070 | "params": [ 1071 | "device" 1072 | ], 1073 | "type": "tag" 1074 | }, 1075 | { 1076 | "params": [ 1077 | "null" 1078 | ], 1079 | "type": "fill" 1080 | } 1081 | ], 1082 | "limit": "", 1083 | "measurement": "smart_attribute", 1084 | "orderByTime": "ASC", 1085 | "policy": "default", 1086 | "refId": "A", 1087 | "resultFormat": "time_series", 1088 | "select": [ 1089 | [ 1090 | { 1091 | "params": [ 1092 | "raw_value" 1093 | ], 1094 | "type": "field" 1095 | }, 1096 | { 1097 | "params": [], 1098 | "type": "last" 1099 | } 1100 | ] 1101 | ], 1102 | "slimit": "", 1103 | "tags": [ 1104 | { 1105 | "key": "name", 1106 | "operator": "=", 1107 | "value": "Power_Cycle_Count" 1108 | } 1109 | ] 1110 | } 1111 | ], 1112 | "title": "Power cycle count", 1113 | "transform": "timeseries_aggregations", 1114 | "type": "table" 1115 | }, 1116 | { 1117 | "columns": [ 1118 | { 1119 | "text": "Avg", 1120 | "value": "avg" 1121 | } 1122 | ], 1123 | "datasource": "${DS_TELEGRAF}", 1124 | "fontSize": "100%", 1125 | "id": 13, 1126 | "links": [], 1127 | "pageSize": 5, 1128 | "scroll": false, 1129 | "showHeader": true, 1130 | "sort": { 1131 | "col": 0, 1132 | "desc": false 1133 | }, 1134 | "span": 2, 1135 | "styles": [ 1136 | { 1137 | "alias": "Time", 1138 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1139 | "pattern": "Time", 1140 | "type": "date" 1141 | }, 1142 | { 1143 | "alias": "", 1144 | "colorMode": null, 1145 | "colors": [ 1146 | "rgba(245, 54, 54, 0.9)", 1147 | "rgba(237, 129, 40, 0.89)", 1148 | "rgba(50, 172, 45, 0.97)" 1149 | ], 1150 | "decimals": 0, 1151 | "pattern": "/.*/", 1152 | "thresholds": [], 1153 | "type": "number", 1154 | "unit": "short" 1155 | } 1156 | ], 1157 | "targets": [ 1158 | { 1159 | "alias": "$tag_device", 1160 | "dsType": "influxdb", 1161 | "groupBy": [ 1162 | { 1163 | "params": [ 1164 | "$__interval" 1165 | ], 1166 | "type": "time" 1167 | }, 1168 | { 1169 | "params": [ 1170 | "device" 1171 | ], 1172 | "type": "tag" 1173 | }, 1174 | { 1175 | "params": [ 1176 | "null" 1177 | ], 1178 | "type": "fill" 1179 | } 1180 | ], 1181 | "limit": "", 1182 | "measurement": "smart_attribute", 1183 | "orderByTime": "ASC", 1184 | "policy": "default", 1185 | "refId": "A", 1186 | "resultFormat": "time_series", 1187 | "select": [ 1188 | [ 1189 | { 1190 | "params": [ 1191 | "raw_value" 1192 | ], 1193 | "type": "field" 1194 | }, 1195 | { 1196 | "params": [], 1197 | "type": "last" 1198 | } 1199 | ] 1200 | ], 1201 | "slimit": "", 1202 | "tags": [ 1203 | { 1204 | "key": "name", 1205 | "operator": "=", 1206 | "value": "Start_Stop_Count" 1207 | } 1208 | ] 1209 | } 1210 | ], 1211 | "title": "Start stop count", 1212 | "transform": "timeseries_aggregations", 1213 | "type": "table" 1214 | }, 1215 | { 1216 | "columns": [ 1217 | { 1218 | "text": "Avg", 1219 | "value": "avg" 1220 | } 1221 | ], 1222 | "datasource": "${DS_TELEGRAF}", 1223 | "fontSize": "100%", 1224 | "id": 16, 1225 | "links": [], 1226 | "pageSize": 5, 1227 | "scroll": false, 1228 | "showHeader": true, 1229 | "sort": { 1230 | "col": 0, 1231 | "desc": false 1232 | }, 1233 | "span": 2, 1234 | "styles": [ 1235 | { 1236 | "alias": "Time", 1237 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 1238 | "pattern": "Time", 1239 | "type": "date" 1240 | }, 1241 | { 1242 | "alias": "", 1243 | "colorMode": null, 1244 | "colors": [ 1245 | "rgba(245, 54, 54, 0.9)", 1246 | "rgba(237, 129, 40, 0.89)", 1247 | "rgba(50, 172, 45, 0.97)" 1248 | ], 1249 | "decimals": 0, 1250 | "pattern": "/.*/", 1251 | "thresholds": [], 1252 | "type": "number", 1253 | "unit": "percent" 1254 | } 1255 | ], 1256 | "targets": [ 1257 | { 1258 | "alias": "$tag_device", 1259 | "dsType": "influxdb", 1260 | "groupBy": [ 1261 | { 1262 | "params": [ 1263 | "$__interval" 1264 | ], 1265 | "type": "time" 1266 | }, 1267 | { 1268 | "params": [ 1269 | "device" 1270 | ], 1271 | "type": "tag" 1272 | }, 1273 | { 1274 | "params": [ 1275 | "null" 1276 | ], 1277 | "type": "fill" 1278 | } 1279 | ], 1280 | "limit": "", 1281 | "measurement": "smart_attribute", 1282 | "orderByTime": "ASC", 1283 | "policy": "default", 1284 | "refId": "A", 1285 | "resultFormat": "time_series", 1286 | "select": [ 1287 | [ 1288 | { 1289 | "params": [ 1290 | "raw_value" 1291 | ], 1292 | "type": "field" 1293 | }, 1294 | { 1295 | "params": [], 1296 | "type": "last" 1297 | } 1298 | ] 1299 | ], 1300 | "slimit": "", 1301 | "tags": [ 1302 | { 1303 | "key": "name", 1304 | "operator": "=", 1305 | "value": "Perc_Avail_Resrvd_Space" 1306 | } 1307 | ] 1308 | } 1309 | ], 1310 | "title": "SSD available reserved space", 1311 | "transform": "timeseries_aggregations", 1312 | "type": "table" 1313 | } 1314 | ], 1315 | "repeat": null, 1316 | "repeatIteration": null, 1317 | "repeatRowId": null, 1318 | "showTitle": false, 1319 | "title": "Dashboard Row", 1320 | "titleSize": "h6" 1321 | } 1322 | ], 1323 | "schemaVersion": 14, 1324 | "style": "dark", 1325 | "tags": [], 1326 | "templating": { 1327 | "list": [] 1328 | }, 1329 | "time": { 1330 | "from": "now-6h", 1331 | "to": "now" 1332 | }, 1333 | "timepicker": { 1334 | "refresh_intervals": [ 1335 | "5s", 1336 | "10s", 1337 | "30s", 1338 | "1m", 1339 | "5m", 1340 | "15m", 1341 | "30m", 1342 | "1h", 1343 | "2h", 1344 | "1d" 1345 | ], 1346 | "time_options": [ 1347 | "5m", 1348 | "15m", 1349 | "1h", 1350 | "6h", 1351 | "12h", 1352 | "24h", 1353 | "2d", 1354 | "7d", 1355 | "30d" 1356 | ] 1357 | }, 1358 | "timezone": "", 1359 | "title": "HDD stats", 1360 | "version": 10 1361 | } -------------------------------------------------------------------------------- /roles/stats/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | grafana_root_url: null 4 | grafana_secret_key: null 5 | grafana_plugins: [] 6 | telegraf_snmp: null 7 | -------------------------------------------------------------------------------- /roles/stats/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: start grafana 4 | service: 5 | name: grafana 6 | enabled: yes 7 | state: started 8 | 9 | - name: restart grafana 10 | service: 11 | name: grafana 12 | enabled: yes 13 | state: restarted 14 | 15 | - name: start influxdb 16 | service: 17 | name: influxd 18 | enabled: yes 19 | state: started 20 | 21 | - name: restart influxdb 22 | service: 23 | name: influxd 24 | enabled: yes 25 | state: restarted 26 | 27 | - name: start telegraf 28 | service: 29 | name: telegraf 30 | enabled: yes 31 | state: started 32 | 33 | - name: restart telegraf 34 | service: 35 | name: telegraf 36 | enabled: yes 37 | state: restarted 38 | -------------------------------------------------------------------------------- /roles/stats/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install grafana 4 | pkgng: 5 | name: grafana5 6 | state: present 7 | 8 | - name: install influxdb 9 | pkgng: 10 | name: influxdb 11 | state: present 12 | 13 | - name: install telegraf 14 | pkgng: 15 | name: telegraf 16 | state: present 17 | 18 | - name: install other dependencies 19 | pkgng: 20 | name: 21 | - collectd5 22 | - ipmitool 23 | - net-snmp 24 | - smartmontools 25 | state: present 26 | 27 | - name: link snmptranslate to /usr/bin so telegraf can use it 28 | file: 29 | src: /usr/local/bin/snmptranslate 30 | dest: /usr/bin/snmptranslate 31 | state: link 32 | 33 | - name: configure grafana 34 | template: 35 | src: grafana.conf 36 | dest: /usr/local/etc/grafana.conf 37 | owner: root 38 | group: wheel 39 | mode: 0644 40 | notify: restart grafana 41 | tags: 42 | - config 43 | 44 | - name: install grafana plugins 45 | command: grafana-cli plugins install {{ item }} 46 | loop: "{{ grafana_plugins }}" 47 | 48 | - name: configure influxdb 49 | template: 50 | src: influxd.conf 51 | dest: /usr/local/etc/influxd.conf 52 | owner: root 53 | group: wheel 54 | mode: 0644 55 | notify: restart influxdb 56 | tags: 57 | - config 58 | 59 | - name: configure telegraf 60 | template: 61 | src: telegraf.conf 62 | dest: /usr/local/etc/telegraf.conf 63 | owner: root 64 | group: wheel 65 | mode: 0644 66 | notify: restart telegraf 67 | tags: 68 | - config 69 | 70 | - name: enable influxdb 71 | service: 72 | name: influxd 73 | enabled: yes 74 | notify: start influxdb 75 | 76 | - name: enable telegraf 77 | service: 78 | name: telegraf 79 | enabled: yes 80 | notify: start telegraf 81 | 82 | - name: enable grafana 83 | service: 84 | name: grafana 85 | enabled: yes 86 | notify: start grafana 87 | 88 | - name: flush handlers to start influxdb before creating database 89 | meta: flush_handlers 90 | 91 | - name: create influxdb databases 92 | command: influx -execute 'CREATE DATABASE {{ item }}' 93 | loop: 94 | - collectd 95 | - telegraf 96 | -------------------------------------------------------------------------------- /roles/stats/templates/grafana.conf: -------------------------------------------------------------------------------- 1 | ##################### Grafana Configuration Example ##################### 2 | # 3 | # Everything has defaults so you only need to uncomment things you want to 4 | # change 5 | 6 | # possible values : production, development 7 | ; app_mode = production 8 | 9 | # instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty 10 | ; instance_name = ${HOSTNAME} 11 | 12 | #################################### Paths #################################### 13 | [paths] 14 | # Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used) 15 | data = /var/db/grafana/ 16 | 17 | # Directory where grafana can store logs 18 | logs = /var/log/grafana/ 19 | 20 | # Directory where grafana will automatically scan and look for plugins 21 | plugins = /var/db/grafana/plugins 22 | 23 | # folder that contains provisioning config files that grafana will apply on startup and while running. 24 | provisioning = /var/db/grafana/provisioning 25 | 26 | #################################### Server #################################### 27 | [server] 28 | # Protocol (http, https, socket) 29 | ;protocol = http 30 | 31 | # The ip address to bind to, empty will bind to all interfaces 32 | ;http_addr = 33 | 34 | # The http port to use 35 | ;http_port = 3000 36 | 37 | # The public facing domain name used to access grafana from a browser 38 | ;domain = localhost 39 | 40 | # Redirect to correct domain if host header does not match domain 41 | # Prevents DNS rebinding attacks 42 | ;enforce_domain = false 43 | 44 | # The full public facing url you use in browser, used for redirects and emails 45 | # If you use reverse proxy and sub path specify full url (with sub path) 46 | root_url = {{ grafana_root_url }} 47 | 48 | # Log web requests 49 | ;router_logging = false 50 | 51 | # the path relative working path 52 | ;static_root_path = public 53 | 54 | # enable gzip 55 | ;enable_gzip = false 56 | 57 | # https certs & key file 58 | ;cert_file = 59 | ;cert_key = 60 | 61 | # Unix socket path 62 | ;socket = 63 | 64 | #################################### Database #################################### 65 | [database] 66 | # You can configure the database connection by specifying type, host, name, user and password 67 | # as seperate properties or as on string using the url propertie. 68 | 69 | # Either "mysql", "postgres" or "sqlite3", it's your choice 70 | ;type = sqlite3 71 | ;host = 127.0.0.1:3306 72 | ;name = grafana 73 | ;user = root 74 | # If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;""" 75 | ;password = 76 | 77 | # Use either URL or the previous fields to configure the database 78 | # Example: mysql://user:secret@host:port/database 79 | ;url = 80 | 81 | # For "postgres" only, either "disable", "require" or "verify-full" 82 | ;ssl_mode = disable 83 | 84 | # For "sqlite3" only, path relative to data_path setting 85 | ;path = grafana.db 86 | 87 | # Max idle conn setting default is 2 88 | ;max_idle_conn = 2 89 | 90 | # Max conn setting default is 0 (mean not set) 91 | ;max_open_conn = 92 | 93 | # Set to true to log the sql calls and execution times. 94 | log_queries = 95 | 96 | #################################### Session #################################### 97 | [session] 98 | # Either "memory", "file", "redis", "mysql", "postgres", default is "file" 99 | ;provider = file 100 | 101 | # Provider config options 102 | # memory: not have any config yet 103 | # file: session dir path, is relative to grafana data_path 104 | # redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=grafana` 105 | # mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1:3306)/database_name` 106 | # postgres: user=a password=b host=localhost port=5432 dbname=c sslmode=disable 107 | ;provider_config = sessions 108 | 109 | # Session cookie name 110 | ;cookie_name = grafana_sess 111 | 112 | # If you use session in https only, default is false 113 | ;cookie_secure = false 114 | 115 | # Session life time, default is 86400 116 | ;session_life_time = 86400 117 | 118 | #################################### Data proxy ########################### 119 | [dataproxy] 120 | 121 | # This enables data proxy logging, default is false 122 | ;logging = false 123 | 124 | 125 | #################################### Analytics #################################### 126 | [analytics] 127 | # Server reporting, sends usage counters to stats.grafana.org every 24 hours. 128 | # No ip addresses are being tracked, only simple counters to track 129 | # running instances, dashboard and error counts. It is very helpful to us. 130 | # Change this option to false to disable reporting. 131 | ;reporting_enabled = true 132 | 133 | # Set to false to disable all checks to https://grafana.net 134 | # for new vesions (grafana itself and plugins), check is used 135 | # in some UI views to notify that grafana or plugin update exists 136 | # This option does not cause any auto updates, nor send any information 137 | # only a GET request to http://grafana.com to get latest versions 138 | ;check_for_updates = true 139 | 140 | # Google Analytics universal tracking code, only enabled if you specify an id here 141 | ;google_analytics_ua_id = 142 | 143 | #################################### Security #################################### 144 | [security] 145 | # default admin user, created on startup 146 | ;admin_user = admin 147 | 148 | # default admin password, can be changed before first start of grafana, or in profile settings 149 | ;admin_password = admin 150 | 151 | # used for signing 152 | secret_key = {{ grafana_secret_key }} 153 | 154 | # Auto-login remember days 155 | ;login_remember_days = 7 156 | ;cookie_username = grafana_user 157 | ;cookie_remember_name = grafana_remember 158 | 159 | # disable gravatar profile images 160 | ;disable_gravatar = false 161 | 162 | # data source proxy whitelist (ip_or_domain:port separated by spaces) 163 | ;data_source_proxy_whitelist = 164 | 165 | # disable protection against brute force login attempts 166 | ;disable_brute_force_login_protection = false 167 | 168 | #################################### Snapshots ########################### 169 | [snapshots] 170 | # snapshot sharing options 171 | ;external_enabled = true 172 | ;external_snapshot_url = https://snapshots-origin.raintank.io 173 | ;external_snapshot_name = Publish to snapshot.raintank.io 174 | 175 | # remove expired snapshot 176 | ;snapshot_remove_expired = true 177 | 178 | #################################### Dashboards History ################## 179 | [dashboards] 180 | # Number dashboard versions to keep (per dashboard). Default: 20, Minimum: 1 181 | ;versions_to_keep = 20 182 | 183 | #################################### Users ############################### 184 | [users] 185 | # disable user signup / registration 186 | ;allow_sign_up = true 187 | 188 | # Allow non admin users to create organizations 189 | ;allow_org_create = true 190 | 191 | # Set to true to automatically assign new users to the default organization (id 1) 192 | ;auto_assign_org = true 193 | 194 | # Default role new users will be automatically assigned (if disabled above is set to true) 195 | ;auto_assign_org_role = Viewer 196 | 197 | # Background text for the user field on the login page 198 | ;login_hint = email or username 199 | 200 | # Default UI theme ("dark" or "light") 201 | ;default_theme = dark 202 | 203 | # External user management, these options affect the organization users view 204 | ;external_manage_link_url = 205 | ;external_manage_link_name = 206 | ;external_manage_info = 207 | 208 | # Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard. 209 | ;viewers_can_edit = false 210 | 211 | [auth] 212 | # Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false 213 | ;disable_login_form = false 214 | 215 | # Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false 216 | ;disable_signout_menu = false 217 | 218 | #################################### Anonymous Auth ########################## 219 | [auth.anonymous] 220 | # enable anonymous access 221 | enabled = true 222 | 223 | # specify organization name that should be used for unauthenticated users 224 | ;org_name = Main Org. 225 | 226 | # specify role for unauthenticated users 227 | org_role = Admin 228 | 229 | #################################### Github Auth ########################## 230 | [auth.github] 231 | ;enabled = false 232 | ;allow_sign_up = true 233 | ;client_id = some_id 234 | ;client_secret = some_secret 235 | ;scopes = user:email,read:org 236 | ;auth_url = https://github.com/login/oauth/authorize 237 | ;token_url = https://github.com/login/oauth/access_token 238 | ;api_url = https://api.github.com/user 239 | ;team_ids = 240 | ;allowed_organizations = 241 | 242 | #################################### Google Auth ########################## 243 | [auth.google] 244 | ;enabled = false 245 | ;allow_sign_up = true 246 | ;client_id = some_client_id 247 | ;client_secret = some_client_secret 248 | ;scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email 249 | ;auth_url = https://accounts.google.com/o/oauth2/auth 250 | ;token_url = https://accounts.google.com/o/oauth2/token 251 | ;api_url = https://www.googleapis.com/oauth2/v1/userinfo 252 | ;allowed_domains = 253 | 254 | #################################### Generic OAuth ########################## 255 | [auth.generic_oauth] 256 | ;enabled = false 257 | ;name = OAuth 258 | ;allow_sign_up = true 259 | ;client_id = some_id 260 | ;client_secret = some_secret 261 | ;scopes = user:email,read:org 262 | ;auth_url = https://foo.bar/login/oauth/authorize 263 | ;token_url = https://foo.bar/login/oauth/access_token 264 | ;api_url = https://foo.bar/user 265 | ;team_ids = 266 | ;allowed_organizations = 267 | 268 | #################################### Grafana.com Auth #################### 269 | [auth.grafana_com] 270 | ;enabled = false 271 | ;allow_sign_up = true 272 | ;client_id = some_id 273 | ;client_secret = some_secret 274 | ;scopes = user:email 275 | ;allowed_organizations = 276 | 277 | #################################### Auth Proxy ########################## 278 | [auth.proxy] 279 | ;enabled = false 280 | ;header_name = X-WEBAUTH-USER 281 | ;header_property = username 282 | ;auto_sign_up = true 283 | ;ldap_sync_ttl = 60 284 | ;whitelist = 192.168.1.1, 192.168.2.1 285 | 286 | #################################### Basic Auth ########################## 287 | [auth.basic] 288 | ;enabled = true 289 | 290 | #################################### Auth LDAP ########################## 291 | [auth.ldap] 292 | ;enabled = false 293 | ;config_file = /etc/grafana/ldap.toml 294 | ;allow_sign_up = true 295 | 296 | #################################### SMTP / Emailing ########################## 297 | [smtp] 298 | ;enabled = false 299 | ;host = localhost:25 300 | ;user = 301 | # If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;""" 302 | ;password = 303 | ;cert_file = 304 | ;key_file = 305 | ;skip_verify = false 306 | ;from_address = admin@grafana.localhost 307 | ;from_name = Grafana 308 | # EHLO identity in SMTP dialog (defaults to instance_name) 309 | ;ehlo_identity = dashboard.example.com 310 | 311 | [emails] 312 | ;welcome_email_on_sign_up = false 313 | 314 | #################################### Logging ########################## 315 | [log] 316 | # Either "console", "file", "syslog". Default is console and file 317 | # Use space to separate multiple modes, e.g. "console file" 318 | ;mode = console file 319 | 320 | # Either "debug", "info", "warn", "error", "critical", default is "info" 321 | ;level = info 322 | 323 | # optional settings to set different levels for specific loggers. Ex filters = sqlstore:debug 324 | ;filters = 325 | 326 | 327 | # For "console" mode only 328 | [log.console] 329 | ;level = 330 | 331 | # log line format, valid options are text, console and json 332 | ;format = console 333 | 334 | # For "file" mode only 335 | [log.file] 336 | ;level = 337 | 338 | # log line format, valid options are text, console and json 339 | ;format = text 340 | 341 | # This enables automated log rotate(switch of following options), default is true 342 | ;log_rotate = true 343 | 344 | # Max line number of single file, default is 1000000 345 | ;max_lines = 1000000 346 | 347 | # Max size shift of single file, default is 28 means 1 << 28, 256MB 348 | ;max_size_shift = 28 349 | 350 | # Segment log daily, default is true 351 | ;daily_rotate = true 352 | 353 | # Expired days of log file(delete after max days), default is 7 354 | ;max_days = 7 355 | 356 | [log.syslog] 357 | ;level = 358 | 359 | # log line format, valid options are text, console and json 360 | ;format = text 361 | 362 | # Syslog network type and address. This can be udp, tcp, or unix. If left blank, the default unix endpoints will be used. 363 | ;network = 364 | ;address = 365 | 366 | # Syslog facility. user, daemon and local0 through local7 are valid. 367 | ;facility = 368 | 369 | # Syslog tag. By default, the process' argv[0] is used. 370 | ;tag = 371 | 372 | 373 | #################################### Alerting ############################ 374 | [alerting] 375 | # Disable alerting engine & UI features 376 | ;enabled = true 377 | # Makes it possible to turn off alert rule execution but alerting UI is visible 378 | ;execute_alerts = true 379 | 380 | #################################### Internal Grafana Metrics ########################## 381 | # Metrics available at HTTP API Url /metrics 382 | [metrics] 383 | # Disable / Enable internal metrics 384 | ;enabled = true 385 | 386 | # Publish interval 387 | ;interval_seconds = 10 388 | 389 | # Send internal metrics to Graphite 390 | [metrics.graphite] 391 | # Enable by setting the address setting (ex localhost:2003) 392 | ;address = 393 | ;prefix = prod.grafana.%(instance_name)s. 394 | 395 | #################################### Distributed tracing ############ 396 | [tracing.jaeger] 397 | # Enable by setting the address sending traces to jaeger (ex localhost:6831) 398 | ;address = localhost:6831 399 | # Tag that will always be included in when creating new spans. ex (tag1:value1,tag2:value2) 400 | ;always_included_tag = tag1:value1 401 | # Type specifies the type of the sampler: const, probabilistic, rateLimiting, or remote 402 | ;sampler_type = const 403 | # jaeger samplerconfig param 404 | # for "const" sampler, 0 or 1 for always false/true respectively 405 | # for "probabilistic" sampler, a probability between 0 and 1 406 | # for "rateLimiting" sampler, the number of spans per second 407 | # for "remote" sampler, param is the same as for "probabilistic" 408 | # and indicates the initial sampling rate before the actual one 409 | # is received from the mothership 410 | ;sampler_param = 1 411 | 412 | #################################### Grafana.com integration ########################## 413 | # Url used to to import dashboards directly from Grafana.com 414 | [grafana_com] 415 | ;url = https://grafana.com 416 | 417 | #################################### External image storage ########################## 418 | [external_image_storage] 419 | # Used for uploading images to public servers so they can be included in slack/email messages. 420 | # you can choose between (s3, webdav, gcs, azure_blob, local) 421 | ;provider = 422 | 423 | [external_image_storage.s3] 424 | ;bucket = 425 | ;region = 426 | ;path = 427 | ;access_key = 428 | ;secret_key = 429 | 430 | [external_image_storage.webdav] 431 | ;url = 432 | ;public_url = 433 | ;username = 434 | ;password = 435 | 436 | [external_image_storage.gcs] 437 | ;key_file = 438 | ;bucket = 439 | ;path = 440 | 441 | [external_image_storage.azure_blob] 442 | ;account_name = 443 | ;account_key = 444 | ;container_name = 445 | 446 | [external_image_storage.local] 447 | # does not require any configuration 448 | -------------------------------------------------------------------------------- /roles/stats/templates/influxd.conf: -------------------------------------------------------------------------------- 1 | ### Welcome to the InfluxDB configuration file. 2 | 3 | # The values in this file override the default values used by the system if 4 | # a config option is not specified. The commented out lines are the configuration 5 | # field and the default value used. Uncommenting a line and changing the value 6 | # will change the value used at runtime when the process is restarted. 7 | 8 | # Once every 24 hours InfluxDB will report usage data to usage.influxdata.com 9 | # The data includes a random ID, os, arch, version, the number of series and other 10 | # usage data. No data from user databases is ever transmitted. 11 | # Change this option to true to disable reporting. 12 | # reporting-disabled = false 13 | 14 | # Bind address to use for the RPC service for backup and restore. 15 | # bind-address = "127.0.0.1:8088" 16 | 17 | ### 18 | ### [meta] 19 | ### 20 | ### Controls the parameters for the Raft consensus group that stores metadata 21 | ### about the InfluxDB cluster. 22 | ### 23 | 24 | [meta] 25 | # Where the metadata/raft database is stored 26 | dir = "/var/db/influxdb/meta" 27 | 28 | # Automatically create a default retention policy when creating a database. 29 | # retention-autocreate = true 30 | 31 | # If log messages are printed for the meta service 32 | # logging-enabled = true 33 | 34 | ### 35 | ### [data] 36 | ### 37 | ### Controls where the actual shard data for InfluxDB lives and how it is 38 | ### flushed from the WAL. "dir" may need to be changed to a suitable place 39 | ### for your system, but the WAL settings are an advanced configuration. The 40 | ### defaults should work for most systems. 41 | ### 42 | 43 | [data] 44 | # The directory where the TSM storage engine stores TSM files. 45 | dir = "/var/db/influxdb/data" 46 | 47 | # The directory where the TSM storage engine stores WAL files. 48 | wal-dir = "/var/db/influxdb/wal" 49 | 50 | # The amount of time that a write will wait before fsyncing. A duration 51 | # greater than 0 can be used to batch up multiple fsync calls. This is useful for slower 52 | # disks or when WAL write contention is seen. A value of 0s fsyncs every write to the WAL. 53 | # Values in the range of 0-100ms are recommended for non-SSD disks. 54 | # wal-fsync-delay = "0s" 55 | 56 | 57 | # The type of shard index to use for new shards. The default is an in-memory index that is 58 | # recreated at startup. A value of "tsi1" will use a disk based index that supports higher 59 | # cardinality datasets. 60 | # index-version = "inmem" 61 | 62 | # Trace logging provides more verbose output around the tsm engine. Turning 63 | # this on can provide more useful output for debugging tsm engine issues. 64 | # trace-logging-enabled = false 65 | 66 | # Whether queries should be logged before execution. Very useful for troubleshooting, but will 67 | # log any sensitive data contained within a query. 68 | # query-log-enabled = true 69 | 70 | # Settings for the TSM engine 71 | 72 | # CacheMaxMemorySize is the maximum size a shard's cache can 73 | # reach before it starts rejecting writes. 74 | # Valid size suffixes are k, m, or g (case insensitive, 1024 = 1k). 75 | # Values without a size suffix are in bytes. 76 | # cache-max-memory-size = "1g" 77 | 78 | # CacheSnapshotMemorySize is the size at which the engine will 79 | # snapshot the cache and write it to a TSM file, freeing up memory 80 | # Valid size suffixes are k, m, or g (case insensitive, 1024 = 1k). 81 | # Values without a size suffix are in bytes. 82 | # cache-snapshot-memory-size = "25m" 83 | 84 | # CacheSnapshotWriteColdDuration is the length of time at 85 | # which the engine will snapshot the cache and write it to 86 | # a new TSM file if the shard hasn't received writes or deletes 87 | # cache-snapshot-write-cold-duration = "10m" 88 | 89 | # CompactFullWriteColdDuration is the duration at which the engine 90 | # will compact all TSM files in a shard if it hasn't received a 91 | # write or delete 92 | # compact-full-write-cold-duration = "4h" 93 | 94 | # The maximum number of concurrent full and level compactions that can run at one time. A 95 | # value of 0 results in 50% of runtime.GOMAXPROCS(0) used at runtime. Any number greater 96 | # than 0 limits compactions to that value. This setting does not apply 97 | # to cache snapshotting. 98 | # max-concurrent-compactions = 0 99 | 100 | # The threshold, in bytes, when an index write-ahead log file will compact 101 | # into an index file. Lower sizes will cause log files to be compacted more 102 | # quickly and result in lower heap usage at the expense of write throughput. 103 | # Higher sizes will be compacted less frequently, store more series in-memory, 104 | # and provide higher write throughput. 105 | # Valid size suffixes are k, m, or g (case insensitive, 1024 = 1k). 106 | # Values without a size suffix are in bytes. 107 | # max-index-log-file-size = "1m" 108 | 109 | # The maximum series allowed per database before writes are dropped. This limit can prevent 110 | # high cardinality issues at the database level. This limit can be disabled by setting it to 111 | # 0. 112 | # max-series-per-database = 1000000 113 | 114 | # The maximum number of tag values per tag that are allowed before writes are dropped. This limit 115 | # can prevent high cardinality tag values from being written to a measurement. This limit can be 116 | # disabled by setting it to 0. 117 | # max-values-per-tag = 100000 118 | 119 | # If true, then the mmap advise value MADV_WILLNEED will be provided to the kernel with respect to 120 | # TSM files. This setting has been found to be problematic on some kernels, and defaults to off. 121 | # It might help users who have slow disks in some cases. 122 | # tsm-use-madv-willneed = false 123 | 124 | ### 125 | ### [coordinator] 126 | ### 127 | ### Controls the clustering service configuration. 128 | ### 129 | 130 | [coordinator] 131 | # The default time a write request will wait until a "timeout" error is returned to the caller. 132 | # write-timeout = "10s" 133 | 134 | # The maximum number of concurrent queries allowed to be executing at one time. If a query is 135 | # executed and exceeds this limit, an error is returned to the caller. This limit can be disabled 136 | # by setting it to 0. 137 | # max-concurrent-queries = 0 138 | 139 | # The maximum time a query will is allowed to execute before being killed by the system. This limit 140 | # can help prevent run away queries. Setting the value to 0 disables the limit. 141 | # query-timeout = "0s" 142 | 143 | # The time threshold when a query will be logged as a slow query. This limit can be set to help 144 | # discover slow or resource intensive queries. Setting the value to 0 disables the slow query logging. 145 | # log-queries-after = "0s" 146 | 147 | # The maximum number of points a SELECT can process. A value of 0 will make 148 | # the maximum point count unlimited. This will only be checked every second so queries will not 149 | # be aborted immediately when hitting the limit. 150 | # max-select-point = 0 151 | 152 | # The maximum number of series a SELECT can run. A value of 0 will make the maximum series 153 | # count unlimited. 154 | # max-select-series = 0 155 | 156 | # The maxium number of group by time bucket a SELECT can create. A value of zero will max the maximum 157 | # number of buckets unlimited. 158 | # max-select-buckets = 0 159 | 160 | ### 161 | ### [retention] 162 | ### 163 | ### Controls the enforcement of retention policies for evicting old data. 164 | ### 165 | 166 | [retention] 167 | # Determines whether retention policy enforcement enabled. 168 | # enabled = true 169 | 170 | # The interval of time when retention policy enforcement checks run. 171 | # check-interval = "30m" 172 | 173 | ### 174 | ### [shard-precreation] 175 | ### 176 | ### Controls the precreation of shards, so they are available before data arrives. 177 | ### Only shards that, after creation, will have both a start- and end-time in the 178 | ### future, will ever be created. Shards are never precreated that would be wholly 179 | ### or partially in the past. 180 | 181 | [shard-precreation] 182 | # Determines whether shard pre-creation service is enabled. 183 | # enabled = true 184 | 185 | # The interval of time when the check to pre-create new shards runs. 186 | # check-interval = "10m" 187 | 188 | # The default period ahead of the endtime of a shard group that its successor 189 | # group is created. 190 | # advance-period = "30m" 191 | 192 | ### 193 | ### Controls the system self-monitoring, statistics and diagnostics. 194 | ### 195 | ### The internal database for monitoring data is created automatically if 196 | ### if it does not already exist. The target retention within this database 197 | ### is called 'monitor' and is also created with a retention period of 7 days 198 | ### and a replication factor of 1, if it does not exist. In all cases the 199 | ### this retention policy is configured as the default for the database. 200 | 201 | [monitor] 202 | # Whether to record statistics internally. 203 | # store-enabled = true 204 | 205 | # The destination database for recorded statistics 206 | # store-database = "_internal" 207 | 208 | # The interval at which to record statistics 209 | # store-interval = "10s" 210 | 211 | ### 212 | ### [http] 213 | ### 214 | ### Controls how the HTTP endpoints are configured. These are the primary 215 | ### mechanism for getting data into and out of InfluxDB. 216 | ### 217 | 218 | [http] 219 | # Determines whether HTTP endpoint is enabled. 220 | # enabled = true 221 | 222 | # The bind address used by the HTTP service. 223 | # bind-address = ":8086" 224 | 225 | # Determines whether user authentication is enabled over HTTP/HTTPS. 226 | # auth-enabled = false 227 | 228 | # The default realm sent back when issuing a basic auth challenge. 229 | # realm = "InfluxDB" 230 | 231 | # Determines whether HTTP request logging is enabled. 232 | # log-enabled = true 233 | 234 | # Determines whether the HTTP write request logs should be suppressed when the log is enabled. 235 | # suppress-write-log = false 236 | 237 | # When HTTP request logging is enabled, this option specifies the path where 238 | # log entries should be written. If unspecified, the default is to write to stderr, which 239 | # intermingles HTTP logs with internal InfluxDB logging. 240 | # 241 | # If influxd is unable to access the specified path, it will log an error and fall back to writing 242 | # the request log to stderr. 243 | # access-log-path = "" 244 | 245 | # Determines whether detailed write logging is enabled. 246 | # write-tracing = false 247 | 248 | # Determines whether the pprof endpoint is enabled. This endpoint is used for 249 | # troubleshooting and monitoring. 250 | # pprof-enabled = true 251 | 252 | # Enables a pprof endpoint that binds to localhost:6060 immediately on startup. 253 | # This is only needed to debug startup issues. 254 | # debug-pprof-enabled = false 255 | 256 | # Determines whether HTTPS is enabled. 257 | # https-enabled = false 258 | 259 | # The SSL certificate to use when HTTPS is enabled. 260 | # https-certificate = "/etc/ssl/influxdb.pem" 261 | 262 | # Use a separate private key location. 263 | # https-private-key = "" 264 | 265 | # The JWT auth shared secret to validate requests using JSON web tokens. 266 | # shared-secret = "" 267 | 268 | # The default chunk size for result sets that should be chunked. 269 | # max-row-limit = 0 270 | 271 | # The maximum number of HTTP connections that may be open at once. New connections that 272 | # would exceed this limit are dropped. Setting this value to 0 disables the limit. 273 | # max-connection-limit = 0 274 | 275 | # Enable http service over unix domain socket 276 | # unix-socket-enabled = false 277 | 278 | # The path of the unix domain socket. 279 | # bind-socket = "/var/run/influxdb.sock" 280 | 281 | # The maximum size of a client request body, in bytes. Setting this value to 0 disables the limit. 282 | # max-body-size = 25000000 283 | 284 | # The maximum number of writes processed concurrently. 285 | # Setting this to 0 disables the limit. 286 | # max-concurrent-write-limit = 0 287 | 288 | # The maximum number of writes queued for processing. 289 | # Setting this to 0 disables the limit. 290 | # max-enqueued-write-limit = 0 291 | 292 | # The maximum duration for a write to wait in the queue to be processed. 293 | # Setting this to 0 or setting max-concurrent-write-limit to 0 disables the limit. 294 | # enqueued-write-timeout = 0 295 | 296 | 297 | ### 298 | ### [ifql] 299 | ### 300 | ### Configures the ifql RPC API. 301 | ### 302 | 303 | [ifql] 304 | # Determines whether the RPC service is enabled. 305 | # enabled = true 306 | 307 | # Determines whether additional logging is enabled. 308 | # log-enabled = true 309 | 310 | # The bind address used by the ifql RPC service. 311 | # bind-address = ":8082" 312 | 313 | 314 | ### 315 | ### [logging] 316 | ### 317 | ### Controls how the logger emits logs to the output. 318 | ### 319 | 320 | [logging] 321 | # Determines which log encoder to use for logs. Available options 322 | # are auto, logfmt, and json. auto will use a more a more user-friendly 323 | # output format if the output terminal is a TTY, but the format is not as 324 | # easily machine-readable. When the output is a non-TTY, auto will use 325 | # logfmt. 326 | # format = "auto" 327 | 328 | # Determines which level of logs will be emitted. The available levels 329 | # are error, warn, info, and debug. Logs that are equal to or above the 330 | # specified level will be emitted. 331 | # level = "info" 332 | 333 | # Suppresses the logo output that is printed when the program is started. 334 | # The logo is always suppressed if STDOUT is not a TTY. 335 | # suppress-logo = false 336 | 337 | ### 338 | ### [subscriber] 339 | ### 340 | ### Controls the subscriptions, which can be used to fork a copy of all data 341 | ### received by the InfluxDB host. 342 | ### 343 | 344 | [subscriber] 345 | # Determines whether the subscriber service is enabled. 346 | # enabled = true 347 | 348 | # The default timeout for HTTP writes to subscribers. 349 | # http-timeout = "30s" 350 | 351 | # Allows insecure HTTPS connections to subscribers. This is useful when testing with self- 352 | # signed certificates. 353 | # insecure-skip-verify = false 354 | 355 | # The path to the PEM encoded CA certs file. If the empty string, the default system certs will be used 356 | # ca-certs = "" 357 | 358 | # The number of writer goroutines processing the write channel. 359 | # write-concurrency = 40 360 | 361 | # The number of in-flight writes buffered in the write channel. 362 | # write-buffer-size = 1000 363 | 364 | 365 | ### 366 | ### [[graphite]] 367 | ### 368 | ### Controls one or many listeners for Graphite data. 369 | ### 370 | 371 | [[graphite]] 372 | # Determines whether the graphite endpoint is enabled. 373 | # enabled = false 374 | # database = "graphite" 375 | # retention-policy = "" 376 | # bind-address = ":2003" 377 | # protocol = "tcp" 378 | # consistency-level = "one" 379 | 380 | # These next lines control how batching works. You should have this enabled 381 | # otherwise you could get dropped metrics or poor performance. Batching 382 | # will buffer points in memory if you have many coming in. 383 | 384 | # Flush if this many points get buffered 385 | # batch-size = 5000 386 | 387 | # number of batches that may be pending in memory 388 | # batch-pending = 10 389 | 390 | # Flush at least this often even if we haven't hit buffer limit 391 | # batch-timeout = "1s" 392 | 393 | # UDP Read buffer size, 0 means OS default. UDP listener will fail if set above OS max. 394 | # udp-read-buffer = 0 395 | 396 | ### This string joins multiple matching 'measurement' values providing more control over the final measurement name. 397 | # separator = "." 398 | 399 | ### Default tags that will be added to all metrics. These can be overridden at the template level 400 | ### or by tags extracted from metric 401 | # tags = ["region=us-east", "zone=1c"] 402 | 403 | ### Each template line requires a template pattern. It can have an optional 404 | ### filter before the template and separated by spaces. It can also have optional extra 405 | ### tags following the template. Multiple tags should be separated by commas and no spaces 406 | ### similar to the line protocol format. There can be only one default template. 407 | # templates = [ 408 | # "*.app env.service.resource.measurement", 409 | # # Default template 410 | # "server.*", 411 | # ] 412 | 413 | ### 414 | ### [collectd] 415 | ### 416 | ### Controls one or many listeners for collectd data. 417 | ### 418 | 419 | [[collectd]] 420 | enabled = true 421 | # bind-address = ":25826" 422 | # database = "collectd" 423 | # retention-policy = "" 424 | # 425 | # The collectd service supports either scanning a directory for multiple types 426 | # db files, or specifying a single db file. 427 | typesdb = "/usr/local/share/collectd" 428 | # 429 | # security-level = "none" 430 | # auth-file = "/etc/collectd/auth_file" 431 | 432 | # These next lines control how batching works. You should have this enabled 433 | # otherwise you could get dropped metrics or poor performance. Batching 434 | # will buffer points in memory if you have many coming in. 435 | 436 | # Flush if this many points get buffered 437 | # batch-size = 5000 438 | 439 | # Number of batches that may be pending in memory 440 | # batch-pending = 10 441 | 442 | # Flush at least this often even if we haven't hit buffer limit 443 | # batch-timeout = "10s" 444 | 445 | # UDP Read buffer size, 0 means OS default. UDP listener will fail if set above OS max. 446 | # read-buffer = 0 447 | 448 | # Multi-value plugins can be handled two ways. 449 | # "split" will parse and store the multi-value plugin data into separate measurements 450 | # "join" will parse and store the multi-value plugin as a single multi-value measurement. 451 | # "split" is the default behavior for backward compatability with previous versions of influxdb. 452 | # parse-multivalue-plugin = "split" 453 | ### 454 | ### [opentsdb] 455 | ### 456 | ### Controls one or many listeners for OpenTSDB data. 457 | ### 458 | 459 | [[opentsdb]] 460 | # enabled = false 461 | # bind-address = ":4242" 462 | # database = "opentsdb" 463 | # retention-policy = "" 464 | # consistency-level = "one" 465 | # tls-enabled = false 466 | # certificate= "/etc/ssl/influxdb.pem" 467 | 468 | # Log an error for every malformed point. 469 | # log-point-errors = true 470 | 471 | # These next lines control how batching works. You should have this enabled 472 | # otherwise you could get dropped metrics or poor performance. Only points 473 | # metrics received over the telnet protocol undergo batching. 474 | 475 | # Flush if this many points get buffered 476 | # batch-size = 1000 477 | 478 | # Number of batches that may be pending in memory 479 | # batch-pending = 5 480 | 481 | # Flush at least this often even if we haven't hit buffer limit 482 | # batch-timeout = "1s" 483 | 484 | ### 485 | ### [[udp]] 486 | ### 487 | ### Controls the listeners for InfluxDB line protocol data via UDP. 488 | ### 489 | 490 | [[udp]] 491 | # enabled = false 492 | # bind-address = ":8089" 493 | # database = "udp" 494 | # retention-policy = "" 495 | 496 | # InfluxDB precision for timestamps on received points ("" or "n", "u", "ms", "s", "m", "h") 497 | # precision = "" 498 | 499 | # These next lines control how batching works. You should have this enabled 500 | # otherwise you could get dropped metrics or poor performance. Batching 501 | # will buffer points in memory if you have many coming in. 502 | 503 | # Flush if this many points get buffered 504 | # batch-size = 5000 505 | 506 | # Number of batches that may be pending in memory 507 | # batch-pending = 10 508 | 509 | # Will flush at least this often even if we haven't hit buffer limit 510 | # batch-timeout = "1s" 511 | 512 | # UDP Read buffer size, 0 means OS default. UDP listener will fail if set above OS max. 513 | # read-buffer = 0 514 | 515 | ### 516 | ### [continuous_queries] 517 | ### 518 | ### Controls how continuous queries are run within InfluxDB. 519 | ### 520 | 521 | [continuous_queries] 522 | # Determines whether the continuous query service is enabled. 523 | # enabled = true 524 | 525 | # Controls whether queries are logged when executed by the CQ service. 526 | # log-enabled = true 527 | 528 | # Controls whether queries are logged to the self-monitoring data store. 529 | # query-stats-enabled = false 530 | 531 | # interval for how often continuous queries will be checked if they need to run 532 | # run-interval = "1s" 533 | 534 | ### 535 | ### [tls] 536 | ### 537 | ### Global configuration settings for TLS in InfluxDB. 538 | ### 539 | 540 | [tls] 541 | # Determines the available set of cipher suites. See https://golang.org/pkg/crypto/tls/#pkg-constants 542 | # for a list of available ciphers, which depends on the version of Go (use the query 543 | # SHOW DIAGNOSTICS to see the version of Go used to build InfluxDB). If not specified, uses 544 | # the default settings from Go's crypto/tls package. 545 | # ciphers = [ 546 | # "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", 547 | # "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 548 | # ] 549 | 550 | # Minimum version of the tls protocol that will be negotiated. If not specified, uses the 551 | # default settings from Go's crypto/tls package. 552 | # min-version = "tls1.2" 553 | 554 | # Maximum version of the tls protocol that will be negotiated. If not specified, uses the 555 | # default settings from Go's crypto/tls package. 556 | # max-version = "tls1.2" 557 | -------------------------------------------------------------------------------- /roles/user_customization/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | root_shell: /bin/sh 4 | user_packages: [] 5 | git_repos: [] 6 | -------------------------------------------------------------------------------- /roles/user_customization/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install user packages 4 | pkgng: 5 | name: "{{ item }}" 6 | state: present 7 | loop: "{{ user_packages }}" 8 | 9 | - name: set the user shell 10 | user: 11 | name: root 12 | state: present 13 | shell: "{{ root_shell }}" 14 | 15 | - name: install git repos 16 | git: 17 | repo: "{{ item.remote }}" 18 | dest: "{{ item.path }}" 19 | version: master 20 | accept_hostkey: yes 21 | force: no 22 | update: no 23 | loop: "{{ git_repos }}" 24 | when: item.private is not defined or not item.private 25 | 26 | - name: create private homeshick repos 27 | shell: git init {{ item.path }} && \ 28 | (cd {{ item.path }} && 29 | git remote add origin {{ item.remote }} && 30 | printf '[branch "master"]\n remote = origin\n merge = refs/heads/master' >> .git/config) 31 | args: 32 | creates: "{{ item.path }}" 33 | loop: "{{ git_repos }}" 34 | when: item.private is defined and item.private 35 | -------------------------------------------------------------------------------- /scripts/backup_freenas_db.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function backup { 4 | local date 5 | local version 6 | local hostname 7 | date=$(date +%Y%m%d%H%M%S) 8 | version=$(cat /etc/version) 9 | hostname=$(hostname -s) 10 | cp \ 11 | /data/freenas-v1.db \ 12 | "/mnt/media/backup/FreeNAS/$hostname-$version-$date.db" 13 | } 14 | 15 | backup 16 | -------------------------------------------------------------------------------- /scripts/backup_jails.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | date=$(date +%Y%m%d%H%M%S) 4 | jails=/mnt/jails/iocage/jails 5 | backup=/mnt/media/backup/jails 6 | 7 | function cleanup { 8 | local jail=$1 9 | local destination=$2 10 | printf "Failed backing up %s\n" "$jail" >&2 11 | if [[ -n $destination ]]; then 12 | rm -rf "$destination" 13 | fi 14 | return 1 15 | } 16 | 17 | function backup { 18 | local jail=$1 19 | shift 20 | local destination=$backup/$jail 21 | local jail_root=$jails/$jail/root 22 | local start 23 | local end 24 | start=$(date +%s) 25 | # shellcheck disable=SC2064 26 | trap "cleanup $jail" EXIT 27 | if [[ ! -e $destination ]]; then 28 | mkdir "$destination" 29 | mkdir "$destination/current" 30 | fi 31 | mkdir "$destination/$date" 32 | # shellcheck disable=SC2064 33 | trap "cleanup $jail $destination/$date" EXIT 34 | ( 35 | cd "$jail_root" 36 | rsync \ 37 | --archive \ 38 | --link-dest="$destination/current" \ 39 | --log-file="$destination/$date/rsync.log" \ 40 | "$@" \ 41 | "$destination/$date" 42 | ) 43 | rm -r "$destination/current" 44 | ln -s "$date" "$destination/current" 45 | trap EXIT 46 | printf "Successfully backed up %s\n" "$jail" 47 | end=$(date +%s) 48 | printf "Backup took %d seconds\n" "$((end-start))" >> "$destination/$date/rsync.log" 49 | } 50 | 51 | (set -e; backup rtorrent usr/local/libdata/rtorrent/.rtorrent.session usr/local/www/rutorrent/share) 52 | (set -e; backup sabnzbd usr/local/sabnzbd/sabnzbd.ini) 53 | (set -e; backup sonarr usr/local/sonarr/{nzbdrone.db,nzbdrone.db-shm,nzbdrone.db-wal,config.xml}) 54 | (set -e; backup radarr usr/local/radarr/{nzbdrone.db,nzbdrone.db-shm,nzbdrone.db-wal,config.xml}) 55 | (set -e; backup plex "usr/local/plexdata/Plex Media Server/Preferences.xml" "usr/local/plexdata/Plex Media Server/Plug-in Support/Databases") 56 | (set -e; backup stats var/db/grafana/grafana.db var/db/influxdb) 57 | -------------------------------------------------------------------------------- /site.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: freenas 4 | roles: 5 | - jails_setup 6 | 7 | - hosts: jails 8 | roles: 9 | - pre_setup 10 | - mdns 11 | - user_customization 12 | tags: [all] 13 | 14 | - hosts: media 15 | roles: [media_group] 16 | tags: [media] 17 | 18 | - hosts: reverse-proxy 19 | roles: [reverse_proxy] 20 | tags: [app] 21 | 22 | - hosts: rtorrent 23 | roles: [rtorrent] 24 | tags: [app] 25 | 26 | - hosts: sabnzbd 27 | roles: [sabnzbd] 28 | tags: [app] 29 | 30 | - hosts: plex 31 | roles: [plex] 32 | tags: [app] 33 | 34 | - hosts: sonarr 35 | roles: [sonarr] 36 | tags: [app] 37 | 38 | - hosts: radarr 39 | roles: [radarr] 40 | tags: [app] 41 | 42 | - hosts: dnscrypt-proxy 43 | roles: [dnscrypt-proxy] 44 | tags: [app] 45 | 46 | - hosts: stats 47 | roles: [stats] 48 | tags: [app] 49 | --------------------------------------------------------------------------------