inital commit

This commit is contained in:
CPunch 2022-10-30 14:01:10 -05:00
commit 9506f24bcc
30 changed files with 769 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
hosts

57
run.yaml Normal file
View File

@ -0,0 +1,57 @@
---
- hosts: all
become: yes
vars_prompt:
- name: auth_enabled
prompt: enable nginx authentication headers? (y/n)
private: no
- name: duck_enabled
prompt: use DuckDNS? (y/n)
private: no
pre_tasks:
- pause:
prompt: "nginx auth username"
when: auth_enabled == "y"
register: prompt
- set_fact:
auth_username: "{{ prompt.user_input }}"
when: auth_enabled == "y"
- pause:
prompt: "nginx auth password"
when: auth_enabled == "y"
register: prompt
- set_fact:
auth_password: "{{ prompt.user_input }}"
when: auth_enabled == "y"
- pause:
prompt: "DuckDNS Token"
when: duck_enabled == "y"
register: prompt
- set_fact:
duck_token: "{{ prompt.user_input }}"
when: duck_enabled == "y"
- pause:
prompt: "DuckDNS Subdomain (including .duckdns.org)"
when: duck_enabled == "y"
register: prompt
- set_fact:
duck_domain: "{{ prompt.user_input }}"
when: duck_enabled == "y"
tasks:
- import_tasks: tasks/essential.yaml
- import_tasks: tasks/firewall.yaml
- import_tasks: tasks/homer.yaml
- import_tasks: tasks/deluge.yaml
- import_tasks: tasks/jackett.yaml
- import_tasks: tasks/radarr.yaml
- import_tasks: tasks/sonarr.yaml
- import_tasks: tasks/jellyfin.yaml
- import_tasks: tasks/openbooks.yaml
- import_tasks: tasks/nginx.yaml

View File

@ -0,0 +1,26 @@
{
"Port": 9117,
"AllowExternal": true,
"AllowCORS": false,
"APIKey": null,
"AdminPassword": null,
"InstanceId": null,
"BlackholeDir": null,
"UpdateDisabled": false,
"UpdatePrerelease": false,
"BasePathOverride": "/jackett",
"BaseUrlOverride": null,
"CacheEnabled": true,
"CacheTtl": 2100,
"CacheMaxResultsPerIndexer": 1000,
"FlareSolverrUrl": null,
"FlareSolverrMaxTimeout": 55000,
"OmdbApiKey": null,
"OmdbApiUrl": null,
"ProxyType": 0,
"ProxyUrl": null,
"ProxyPort": null,
"ProxyUsername": null,
"ProxyPassword": null,
"ProxyIsAnonymous": true
}

16
static/docker/deluge.yaml Normal file
View File

@ -0,0 +1,16 @@
---
version: "2.1"
services:
deluge:
image: lscr.io/linuxserver/deluge:latest
container_name: deluge
environment:
- PUID=1000
- PGID=1000
- DELUGE_LOGLEVEL=error #optional
volumes:
- /infra/deluge/config:/config
- /infra/downloads:/downloads
ports:
- 8001:8112
restart: unless-stopped

14
static/docker/homer.yaml Normal file
View File

@ -0,0 +1,14 @@
---
version: "2"
services:
homer:
image: b4bz/homer:latest
container_name: homer
volumes:
- /infra/homer:/www/assets
ports:
- 8000:8080
user: 1000:1000 # default
environment:
- INIT_ASSETS=1 # default
restart: unless-stopped

View File

@ -0,0 +1,16 @@
---
version: "2.1"
services:
jackett:
image: lscr.io/linuxserver/jackett:latest
container_name: jackett
environment:
- PUID=1000
- PGID=1000
- AUTO_UPDATE=true #optional
volumes:
- /infra/jackett/config:/config
- /infra/downloads:/downloads
ports:
- 8005:9117
restart: unless-stopped

View File

@ -0,0 +1,16 @@
---
version: "2.1"
services:
jellyfin:
image: lscr.io/linuxserver/jellyfin:latest
container_name: jellyfin
environment:
- PUID=1000
- PGID=1000
volumes:
- /infra/jellyfin/config:/config
- /infra/downloads/tvshows:/data/tvshows
- /infra/downloads/movies:/data/movies
ports:
- 8006:8096
restart: unless-stopped

View File

@ -0,0 +1,13 @@
---
version: "3.3"
services:
openbooks:
image: evanbuss/openbooks:latest
container_name: openbooks
volumes:
- /infra/downloads/books:/books
ports:
- 8004:80
environment:
- BASE_PATH=/openbooks/
restart: unless-stopped

14
static/docker/radarr.yaml Normal file
View File

@ -0,0 +1,14 @@
---
version: "2.1"
services:
radarr:
image: lscr.io/linuxserver/radarr:latest
container_name: radarr
environment:
- PUID=1000
- PGID=1000
volumes:
- /infra/radarr:/config
- /infra/downloads:/downloads #optional
network_mode: host
restart: unless-stopped

14
static/docker/sonarr.yaml Normal file
View File

@ -0,0 +1,14 @@
---
version: "2.1"
services:
sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
environment:
- PUID=1000
- PGID=1000
volumes:
- /infra/sonarr:/config
- /infra/downloads:/downloads #optional
network_mode: host
restart: unless-stopped

View File

@ -0,0 +1,8 @@
[sshd]
enabled = true
[nginx-http-auth]
enabled = true
[nginx-botsearch]
enabled = true

49
static/homer/config.yml Normal file
View File

@ -0,0 +1,49 @@
---
title: "Yarr'!"
subtitle: "a poor man's pirate box"
icon: "fas fa-skull-crossbones"
columns: "3" # "auto" or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)
# Set the default layout and color scheme
defaults:
layout: columns # Either 'columns', or 'list'
colorTheme: dark # One of 'auto', 'light', or 'dark'
header: true
footer: <p>Piracy is not the problem, obscurity is.</p>
# Optional theming
theme: default # 'default' or one of the themes available in 'src/assets/themes'.
services:
- name: "Torrent"
icon: "fas fa-code-branch"
items:
- name: "Deluge"
icon: "fa-solid fa-download"
subtitle: "Torrent client"
url: "/deluge/"
- name: "Jackett"
icon: "fa-solid fa-shirt"
subtitle: "Torrent tracker"
url: "/jackett/UI/Dashboard"
- name: "Radarr"
icon: "fa-solid fa-satellite-dish"
subtitle: "Movie downloader"
url: "/radarr/"
- name: "Sonarr"
icon: "fa-solid fa-satellite-dish"
subtitle: "TV Show downloader"
url: "/sonarr/"
- name: "Media"
icon: "fa-solid fa-compact-disk"
items:
- name: "OpenBooks"
icon: "fa-solid fa-book-skull"
subtitle: "eBook tracker and downloader"
url: "/openbooks/"
- name: "Jellyfin"
icon: "fa-solid fa-photo-film"
subtitle: "Media vault"
url: "/jellyfin/"

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<NetworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<RequireHttps>false</RequireHttps>
<BaseUrl>/jellyfin/</BaseUrl>
<PublicHttpsPort>8920</PublicHttpsPort>
<HttpServerPortNumber>8096</HttpServerPortNumber>
<HttpsPortNumber>8920</HttpsPortNumber>
<EnableHttps>false</EnableHttps>
<PublicPort>8096</PublicPort>
<UPnPCreateHttpPortMap>false</UPnPCreateHttpPortMap>
<UDPPortRange />
<EnableIPV6>false</EnableIPV6>
<EnableIPV4>true</EnableIPV4>
<EnableSSDPTracing>false</EnableSSDPTracing>
<SSDPTracingFilter />
<UDPSendCount>2</UDPSendCount>
<UDPSendDelay>100</UDPSendDelay>
<IgnoreVirtualInterfaces>true</IgnoreVirtualInterfaces>
<VirtualInterfaceNames>vEthernet*</VirtualInterfaceNames>
<GatewayMonitorPeriod>60</GatewayMonitorPeriod>
<TrustAllIP6Interfaces>false</TrustAllIP6Interfaces>
<HDHomerunPortRange />
<PublishedServerUriBySubnet />
<AutoDiscoveryTracing>false</AutoDiscoveryTracing>
<AutoDiscovery>true</AutoDiscovery>
<RemoteIPFilter />
<IsRemoteIPFilterBlacklist>false</IsRemoteIPFilterBlacklist>
<EnableUPnP>false</EnableUPnP>
<EnableRemoteAccess>true</EnableRemoteAccess>
<LocalNetworkSubnets />
<LocalNetworkAddresses />
<KnownProxies />
<EnablePublishedServerUriByRequest>false</EnablePublishedServerUriByRequest>
</NetworkConfiguration>

45
static/nginx/nginx.conf Normal file
View File

@ -0,0 +1,45 @@
user www-data;
worker_processes auto;
include /etc/nginx/modules-enabled/*.conf;
pid /run/nginx.pid;
events {
worker_connections 768;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

View File

@ -0,0 +1,32 @@
proxy_connect_timeout 59s;
proxy_send_timeout 600;
proxy_read_timeout 36000s; ## Timeout after 10 hours
proxy_buffer_size 64k;
proxy_buffers 16 32k;
proxy_pass_header Set-Cookie;
proxy_hide_header Vary;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_set_header Accept-Encoding '';
proxy_ignore_headers Cache-Control Expires;
proxy_set_header Referer $http_referer;
proxy_set_header Host $host;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Port '443';
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Authorization '';
proxy_buffering off;
proxy_redirect off;
## Required for Plex WebSockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

84
static/nginx/sites.conf Normal file
View File

@ -0,0 +1,84 @@
server {
listen 0.0.0.0:80 default_server;
location /deluge {
return 302 $scheme://$host/deluge/;
}
location /deluge/ {
proxy_pass http://localhost:8001/;
proxy_set_header X-Deluge-Base "/deluge/";
include restrict-auth.conf;
include proxy-control.conf;
add_header X-Frame-Options SAMEORIGIN;
}
location /radarr {
proxy_pass http://localhost:8002/radarr;
include restrict-auth.conf;
include proxy-control.conf;
add_header X-Frame-Options SAMEORIGIN;
}
# allow radarr api to be reached
location /radarr/api {
proxy_pass http://localhost:8002/radarr/api;
include restrict-auth.conf;
include proxy-control.conf;
add_header X-Frame-Options SAMEORIGIN;
}
location /sonarr {
proxy_pass http://localhost:8003/sonarr;
include restrict-auth.conf;
include proxy-control.conf;
add_header X-Frame-Options SAMEORIGIN;
}
# allow sonarr api to be reached
location /sonarr/api {
proxy_pass http://localhost:8003/sonarr/api;
include restrict-auth.conf;
include proxy-control.conf;
add_header X-Frame-Options SAMEORIGIN;
}
location /openbooks {
proxy_pass http://localhost:8004/openbooks/;
include restrict-auth.conf;
include proxy-control.conf;
add_header X-Frame-Options SAMEORIGIN;
}
# openbooks uses a subdirectory for websocket connections
location /openbooks/ws {
proxy_pass http://localhost:8004/openbooks/ws;
include restrict-auth.conf;
include proxy-control.conf;
add_header X-Frame-Options SAMEORIGIN;
}
location /jackett {
proxy_pass http://localhost:8005/jackett;
include restrict-auth.conf;
include proxy-control.conf;
add_header X-Frame-Options SAMEORIGIN;
}
# jellyfin doesn't require auth headers (it has its own authentication system)
location /jellyfin {
return 302 $scheme://$host/jellyfin/;
}
location /jellyfin/ {
proxy_pass http://localhost:8006;
include proxy-control.conf;
}
location / {
proxy_pass http://localhost:8000/;
include restrict-auth.conf;
include proxy-control.conf;
add_header X-Frame-Options SAMEORIGIN;
}
}

16
static/radarr/config.xml Normal file
View File

@ -0,0 +1,16 @@
<Config>
<LogLevel>info</LogLevel>
<UrlBase>/radarr</UrlBase>
<UpdateMechanism>Docker</UpdateMechanism>
<BindAddress>*</BindAddress>
<Port>8002</Port>
<SslPort>1337</SslPort>
<EnableSsl>False</EnableSsl>
<LaunchBrowser>False</LaunchBrowser>
<ApiKey></ApiKey>
<AuthenticationMethod>None</AuthenticationMethod>
<Branch>master</Branch>
<SslCertPath></SslCertPath>
<SslCertPassword></SslCertPassword>
<InstanceName>Radarr</InstanceName>
</Config>

16
static/sonarr/config.xml Normal file
View File

@ -0,0 +1,16 @@
<Config>
<LogLevel>info</LogLevel>
<UrlBase>/sonarr</UrlBase>
<UpdateMechanism>Docker</UpdateMechanism>
<BindAddress>*</BindAddress>
<Port>8003</Port>
<SslPort>1337</SslPort>
<EnableSsl>False</EnableSsl>
<LaunchBrowser>False</LaunchBrowser>
<ApiKey></ApiKey>
<AuthenticationMethod>None</AuthenticationMethod>
<Branch>master</Branch>
<SslCertPath></SslCertPath>
<SslCertPassword></SslCertPassword>
<InstanceName>Sonarr</InstanceName>
</Config>

15
tasks/deluge.yaml Normal file
View File

@ -0,0 +1,15 @@
---
- name: Make deluge dir
file:
name: /infra/deluge/config
state: directory
owner: 1000
- name: Copy deluge docker-compose
copy:
src: static/docker/deluge.yaml
dest: /infra/deluge/docker-compose.yaml
- name: Build & start deluge
community.docker.docker_compose:
project_src: /infra/deluge

43
tasks/essential.yaml Normal file
View File

@ -0,0 +1,43 @@
---
- name: Upgrade Packages
apt:
update_cache: yes
upgrade: full
- name: Install required software
package:
name:
- apache2-utils
- python3-passlib
- nginx
- fail2ban
- docker
- docker-compose
- ufw
- curl
- python3-certbot-nginx
- name: Make downloads directory
file:
name: /infra/downloads
state: directory
owner: 1000
- name: Make downloads/movies directory
file:
name: /infra/downloads/movies
state: directory
owner: 1000
- name: Make downloads/tvshows directory
file:
name: /infra/downloads/tvshows
state: directory
owner: 1000
- name: Make infra user
user:
name: infra
comment: infrastructure
uid: 1000
state: present

45
tasks/firewall.yaml Normal file
View File

@ -0,0 +1,45 @@
---
- name: Allow port 22
community.general.ufw:
rule: allow
port: '22'
proto: tcp
- name: Allow port 80
community.general.ufw:
rule: allow
port: '80'
proto: tcp
- name: Allow port 443
community.general.ufw:
rule: allow
port: '443'
proto: tcp
- name: Allow port 6881
community.general.ufw:
rule: allow
port: '6881'
proto: tcp
- name: Allow port 6881/udp
community.general.ufw:
rule: allow
port: '6881'
proto: udp
- name: Startup UFW
community.general.ufw:
state: enabled
- name: Copy fail2ban jail config
copy:
src: static/fail2ban/jails.local
dest: /etc/fail2ban/jail.d/jails.local
- name: Enable fail2ban service
systemd:
name: fail2ban
enabled: yes
state: started

15
tasks/homer.yaml Normal file
View File

@ -0,0 +1,15 @@
---
- name: Copy homer dir
copy:
src: static/homer
dest: /infra
owner: 1000
- name: Copy homer docker-compose
copy:
src: static/docker/homer.yaml
dest: /infra/homer/docker-compose.yaml
- name: Build & start homer
community.docker.docker_compose:
project_src: /infra/homer

22
tasks/jackett.yaml Normal file
View File

@ -0,0 +1,22 @@
---
- name: Make jackett dir
file:
name: /infra/jackett/config
state: directory
owner: 1000
- name: Copy jackett config
copy:
src: static/Jackett
dest: /infra/jackett/config
owner: 1000
force: no
- name: Copy jackett docker-compose
copy:
src: static/docker/jackett.yaml
dest: /infra/jackett/docker-compose.yaml
- name: Build & start jackett
community.docker.docker_compose:
project_src: /infra/jackett

21
tasks/jellyfin.yaml Normal file
View File

@ -0,0 +1,21 @@
---
- name: Make jellyfin dir
file:
name: /infra/jellyfin/config
state: directory
owner: 1000
- name: Copy jellyfin base config
copy:
src: static/jellyfin/network.xml
dest: /infra/jellyfin/config/network.xml
owner: 1000
- name: Copy jellyfin docker-compose
copy:
src: static/docker/jellyfin.yaml
dest: /infra/jellyfin/docker-compose.yaml
- name: Build & start jellyfin
community.docker.docker_compose:
project_src: /infra/jellyfin

74
tasks/nginx.yaml Normal file
View File

@ -0,0 +1,74 @@
---
- name: Remove default nginx config
file:
name: /etc/nginx/sites-enabled
state: absent
- name: Restore nginx/conf.d
file:
name: /etc/nginx/conf.d
state: directory
- name: Install system nginx config
copy:
src: static/nginx/nginx.conf
dest: /etc/nginx/nginx.conf
# helps with proxy-ing services
- name: Install nginx proxy-control.conf
copy:
src: static/nginx/proxy-control.conf
dest: /etc/nginx/proxy-control.conf
- name: Install nginx restrict-conf.conf
template:
src: templates/nginx/restrict-auth.conf
dest: /etc/nginx/restrict-auth.conf
- name: Install nginx config for site proxies
copy:
src: static/nginx/sites.conf
dest: /etc/nginx/conf.d/sites.conf
# locks down services that shouldn't be public (if enabled)
- name: Install nginx passwd file
htpasswd:
path: /etc/nginx/passwdfile
name: "{{ auth_username }}"
password: "{{ auth_password }}"
owner: root
group: www-data
mode: 0640
when: auth_enabled == "y" # only do it when the username is specified
- name: Install updateDuckDNS
template:
src: templates/updateDuckDNS
dest: /infra/updateDuckDNS
mode: u+rx
when: duck_enabled == "y"
# update duckdns daily
- name: Install DuckDNS cronjob
cron:
name: Update DuckDNS
minute: 0
hour: 1
job: /infra/updateDuckDNS
when: duck_enabled == "y"
# go ahead and run the update (before running cerbot)
- name: Setup DuckDNS
shell: "/infra/updateDuckDNS"
when: duck_enabled == "y"
# certbot is a life saver. thank you certbot devs!
- name: Setup certbot
shell: "certbot --nginx --non-interactive --agree-tos -m do_not_contact@proton.me -d {{ duck_domain }}"
when: duck_enabled == "y"
- name: Reload Nginx
systemd:
name: nginx
enabled: yes
state: restarted

21
tasks/openbooks.yaml Normal file
View File

@ -0,0 +1,21 @@
---
- name: Make downloads/books dir
file:
name: /infra/downloads/books
state: directory
owner: 1000
- name: Make openbooks dir
file:
name: /infra/openbooks
state: directory
owner: 1000
- name: Copy openbooks docker-compose
copy:
src: static/docker/openbooks.yaml
dest: /infra/openbooks/docker-compose.yaml
- name: Build & start openbooks
community.docker.docker_compose:
project_src: /infra/openbooks

16
tasks/radarr.yaml Normal file
View File

@ -0,0 +1,16 @@
---
- name: Copy radarr dir
copy:
src: static/radarr
dest: /infra
owner: 1000
force: no
- name: Copy radarr docker-compose
copy:
src: static/docker/radarr.yaml
dest: /infra/radarr/docker-compose.yaml
- name: Build & start radarr
community.docker.docker_compose:
project_src: /infra/radarr

16
tasks/sonarr.yaml Normal file
View File

@ -0,0 +1,16 @@
---
- name: Copy sonarr dir
copy:
src: static/sonarr
dest: /infra
owner: 1000
force: no
- name: Copy sonarr docker-compose
copy:
src: static/docker/sonarr.yaml
dest: /infra/sonarr/docker-compose.yaml
- name: Build & start sonarr
community.docker.docker_compose:
project_src: /infra/sonarr

View File

@ -0,0 +1,8 @@
{% if "y" == auth_enabled %}
satisfy any;
allow 127.0.0.1;
allow ::1;
deny all;
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/passwdfile;
{% endif %}

2
templates/updateDuckDNS Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
curl -I https://duckdns.org/update/{{ duck_domain }}/{{ duck_token }}