Compare commits

...

30 Commits

Author SHA1 Message Date
Lukáš Kucharczyk b43560720e
README: add Radarr 2021-06-21 13:47:31 +02:00
Lukáš Kucharczyk 5e5cb703a6
authelia: radarr=two_factor 2021-06-21 13:09:40 +02:00
Lukáš Kucharczyk 9c50a6dcaf
radarr: add related vars 2021-06-21 13:09:25 +02:00
Lukáš Kucharczyk 2269007083
radarr: add nginx conf 2021-06-21 13:09:11 +02:00
Lukáš Kucharczyk 6ebb25af72
radarr: add role 2021-06-21 13:08:59 +02:00
Lukáš Kucharczyk b8364d8163
README: sort alphabetically 2021-06-21 12:02:32 +02:00
Lukáš Kucharczyk 7a0a240ad8
readme: add portainer 2021-06-21 12:02:00 +02:00
Lukáš Kucharczyk 2a8b5464e6
jellyfin, nginx, openldap: do not restart 2021-06-21 11:55:06 +02:00
Lukáš Kucharczyk e43907992a
openldap: remove cruft 2021-06-21 11:55:05 +02:00
Lukáš Kucharczyk 6638b4d357
openldap: move above portainer 2021-06-21 11:55:04 +02:00
Lukáš Kucharczyk bdb6b109af
docker: add convenience packages 2021-06-21 11:55:03 +02:00
Lukáš Kucharczyk 17a5d0550d
authelia: secure portainer, keycloak, allow local 2021-06-21 11:55:02 +02:00
Lukáš Kucharczyk 45f14658e4
portainer: allow access to ldap 2021-06-21 11:55:01 +02:00
Lukáš Kucharczyk a13a7adf67
nginx: make sure https redirect works 2021-06-21 11:55:00 +02:00
Lukáš Kucharczyk 069314f9d6
minor: fix space 2021-06-21 11:54:59 +02:00
Lukáš Kucharczyk c418b61ede
Improve networks
Create a single external network called "external".
Create container-specific networks.
Only a few containers need access to these.
So far: openldap, postgres.
2021-06-21 11:54:58 +02:00
Lukáš Kucharczyk f5824a5ffe
portainer: copy nginx conf 2021-06-21 11:54:57 +02:00
Lukáš Kucharczyk 1ad9787b17
portainer: add nginx-internal network 2021-06-21 11:54:56 +02:00
Lukáš Kucharczyk 2593c84400
Set portainer to one_factor 2021-06-21 11:54:55 +02:00
Lukáš Kucharczyk 6b70fa2587
portainer: add nginx conf 2021-06-21 11:54:54 +02:00
Lukáš Kucharczyk 6702afc8f7
portainer: add main task 2021-06-21 11:54:53 +02:00
Lukáš Kucharczyk 7a17b16980
portainer: add role to playbook 2021-06-21 11:54:52 +02:00
Lukáš Kucharczyk a464d287b7
Fix error introduced in 9cf68c4fda 2021-06-21 09:53:25 +02:00
Lukáš Kucharczyk 1df2e68180 nginx: log subrequests 2021-06-21 06:14:19 +00:00
Lukáš Kucharczyk d72ee10d04
README: add authelia 2021-06-20 21:58:10 +02:00
Lukáš Kucharczyk 9cf68c4fda
authelia: set everything to bypass for now 2021-06-20 21:54:32 +02:00
Lukáš Kucharczyk 90d1065f53
vault: change keycloak admin 2021-06-20 21:53:45 +02:00
Lukáš Kucharczyk a465111aa7
authelia: move proxy config up 2021-06-20 21:53:20 +02:00
Lukáš Kucharczyk 13c9974b4d
Fix authelia-*.conf
The example at https://www.authelia.com/docs/deployment/supported-proxies/nginx.html
does not seem to work. Updated with code from:
https://github.com/linuxserver/docker-swag/blob/master/root/defaults/authelia-server.conf
https://github.com/linuxserver/docker-swag/blob/master/root/defaults/authelia-location.conf
2021-06-20 20:58:09 +02:00
Lukáš Kucharczyk ff90202646
provision.sh: add fish hashbang 2021-06-20 20:57:30 +02:00
23 changed files with 189 additions and 76 deletions

View File

@ -12,11 +12,14 @@ homelab.
=== Containers === Containers
* NGINX * Authelia
* Jellyfin * Jellyfin
* OpenLDAP
* PostgreSQL
* Keycloak * Keycloak
* NGINX
* OpenLDAP
* Portainer
* PostgreSQL
* Radarr
=== Testing === Testing
To run locally, specify the inventory file with `-i hosts`. To run locally, specify the inventory file with `-i hosts`.

View File

@ -13,4 +13,9 @@ pgid: "1000"
tz: "Europe/Prague" tz: "Europe/Prague"
media: media:
tv: "{{ data_folder }}/media/tv" tv: "{{ data_folder }}/media/tv"
movies: "{{ data_folder }}/media/movies" movies: "{{ data_folder }}/media/movies"
downloads:
nzb: "{{ data_folder }}/downloads/nzb"
torrent: "{{ data_folder }}/downloads/torrent"
torrent_blackhole: "{{ data_folder }}/downloads/blackhole"
music: "{{ data_folder }}/downloads/music"

View File

@ -3,11 +3,13 @@
roles: roles:
- docker - docker
- nginx - nginx
- jellyfin
- openldap - openldap
- portainer
- jellyfin
- postgres - postgres
- authelia - authelia
- keycloak - keycloak
- radarr
vars_files: vars_files:
- vault/certs/{{ base_domain }}.yml - vault/certs/{{ base_domain }}.yml
- vault/passwords.yml - vault/passwords.yml

View File

@ -1 +1,2 @@
#!/bin/env fish
ANSIBLE_VAULT_PASSWORD_FILE=(pass show ansible-homelab | psub) vagrant provision ANSIBLE_VAULT_PASSWORD_FILE=(pass show ansible-homelab | psub) vagrant provision

View File

@ -17,8 +17,8 @@
ports: ports:
- "9091:9091" - "9091:9091"
networks: networks:
- name: bridge - name: external
- name: nginx-internal - name: openldap
volumes: volumes:
- "{{ data_folder }}/authelia:/config" - "{{ data_folder }}/authelia:/config"
- name: copy nginx endpoint conf - name: copy nginx endpoint conf

View File

@ -1,14 +1,5 @@
# Basic Authelia Config auth_request /authelia/api/verify;
# Send a subsequent request to Authelia to verify if the user is authenticated
# and has the right permissions to access the resource.
auth_request /authelia;
# Set the `target_url` variable based on the request. It will be used to build the portal
# URL with the correct redirection parameter.
auth_request_set $target_url $scheme://$http_host$request_uri; auth_request_set $target_url $scheme://$http_host$request_uri;
# Set the X-Forwarded-User and X-Forwarded-Groups with the headers
# returned by Authelia for the backends which can consume them.
# This is not safe, as the backend must make sure that they come from the
# proxy. In the future, it's gonna be safe to just use OAuth.
auth_request_set $user $upstream_http_remote_user; auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups; auth_request_set $groups $upstream_http_remote_groups;
auth_request_set $name $upstream_http_remote_name; auth_request_set $name $upstream_http_remote_name;
@ -17,7 +8,4 @@ proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups; proxy_set_header Remote-Groups $groups;
proxy_set_header Remote-Name $name; proxy_set_header Remote-Name $name;
proxy_set_header Remote-Email $email; proxy_set_header Remote-Email $email;
# If Authelia returns 401, then nginx redirects the user to the login portal. error_page 401 =302 https://$http_host/authelia/?rd=$target_url;
# If it returns 200, then the request pass through to the backend.
# For other type of errors, nginx will handle them as usual.
error_page 401 =302 https://auth.{{ base_domain }}/?rd=$target_url;

View File

@ -1,10 +1,17 @@
set $upstream_authelia http://authelia:9091/api/verify; location ^~ /authelia {
include /etc/nginx/snippets/proxy.conf;
set $upstream_authelia authelia;
proxy_pass http://$upstream_authelia:9091;
}
# Virtual endpoint created by nginx to forward auth requests. location = /authelia/api/verify {
location /authelia {
internal; internal;
if ($request_uri ~ [^a-zA-Z0-9_+-=\!@$%&*?~.:#'\;\(\)\[\]]) {
return 401;
}
set $upstream_authelia authelia;
proxy_pass_request_body off; proxy_pass_request_body off;
proxy_pass $upstream_authelia; proxy_pass http://$upstream_authelia:9091;
proxy_set_header Content-Length ""; proxy_set_header Content-Length "";
# Timeout if the real server is dead # Timeout if the real server is dead
@ -19,11 +26,11 @@ location /authelia {
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri; proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Method $request_method; proxy_set_header X-Forwarded-Method $request_method;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri; proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-Ssl on;
proxy_redirect http:// $scheme://; proxy_redirect http:// $scheme://;
proxy_http_version 1.1; proxy_http_version 1.1;

View File

@ -1,7 +1,7 @@
server { server {
listen 80;
server_name auth.{{ base_domain }}; server_name auth.{{ base_domain }};
return 301 https://$host$request_uri; listen 80;
return 301 https://$server_name$request_uri;
} }
server { server {
@ -9,8 +9,8 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
location / { location / {
include /etc/nginx/snippets/proxy.conf;
set $upstream_authelia http://authelia:9091; # This example assumes a Docker deployment set $upstream_authelia http://authelia:9091; # This example assumes a Docker deployment
proxy_pass $upstream_authelia; proxy_pass $upstream_authelia;
include /etc/nginx/snippets/proxy.conf;
} }
} }

View File

@ -26,12 +26,21 @@ authentication_backend:
password: {{ vault_openldap_admin_password }} password: {{ vault_openldap_admin_password }}
access_control: access_control:
default_policy: deny default_policy: deny
networks:
- name: local
networks:
- 192.168.0.0/24
rules: rules:
- domain: - domain: "*.{{ base_domain }}"
- "{{ base_domain }}" networks:
- "*.{{ base_domain }}" - local
- "keycloak.{{ base_domain }}" policy: bypass
policy: deny - domain: portainer.{{ base_domain }}
policy: one_factor
- domain: keycloak.{{ base_domain }}
policy: one_factor
- domain: radarr.{{ base_domain }}
policy: two_factor
session: session:
name: authelia_session name: authelia_session
secret: somerandomsecret secret: somerandomsecret

View File

@ -3,6 +3,9 @@
name: name:
- docker - docker
- python-pip - python-pip
- neovim
- fish
- curlie
state: present state: present
update_cache: true update_cache: true
- name: start - name: start
@ -12,8 +15,9 @@
- name: add user to group - name: add user to group
user: user:
name: lukas name: lukas
groups: docker groups: docker,wheel
append: true append: true
shell: /usr/bin/fish
- name: install python docker - name: install python docker
pip: pip:
name: name:

View File

@ -12,7 +12,7 @@
name: 'jellyfin' name: 'jellyfin'
image: linuxserver/jellyfin image: linuxserver/jellyfin
networks: networks:
- name: nginx-internal - name: external
volumes: volumes:
- "{{ data_folder }}/jellyfin:/config" - "{{ data_folder }}/jellyfin:/config"
- "{{ media.tv }}:/data/tv" - "{{ media.tv }}:/data/tv"
@ -29,7 +29,6 @@
devices: devices:
- /dev/dri:/dev/dri - /dev/dri:/dev/dri
state: started state: started
restart: yes
- name: copy jellyfin nginx config - name: copy jellyfin nginx config
template: template:
src: jellyfin.conf.j2 src: jellyfin.conf.j2

View File

@ -1,6 +1,7 @@
server { server {
server_name "jellyfin.{{ base_domain }}";
listen 80; listen 80;
return 301 https://$host$request_uri; return 301 https://$server_name$request_uri;
} }
server { server {

View File

@ -5,8 +5,9 @@
ports: ports:
- "8080:8080" - "8080:8080"
networks: networks:
- name: external
- name: postgres - name: postgres
- name: nginx-internal - name: openldap
env: env:
"KEYCLOAK_USER": "{{ vault_keycloak_user }}" "KEYCLOAK_USER": "{{ vault_keycloak_user }}"
"KEYCLOAK_PASSWORD": "{{ vault_keycloak_password }}" "KEYCLOAK_PASSWORD": "{{ vault_keycloak_password }}"
@ -20,6 +21,6 @@
- name: copy nginx conf - name: copy nginx conf
template: template:
src: "keycloak.conf.j2" src: "keycloak.conf.j2"
dest: "{{ data_folder }}/nginx/conf.d/{{ role_name}}.{{ base_domain }}.conf" dest: "{{ data_folder }}/nginx/conf.d/{{ role_name }}.{{ base_domain }}.conf"
mode: "755" mode: "755"
notify: reload nginx notify: reload nginx

View File

@ -1,6 +1,7 @@
server { server {
listen 80; server_name "keycloak.{{ base_domain }}";
return 301 https://$host$request_uri; listen 80;
return 301 https://$server_name$request_uri;
} }
server { server {

View File

@ -14,11 +14,11 @@
- name: generate self-signed certs - name: generate self-signed certs
import_tasks: self-signed.yml import_tasks: self-signed.yml
when: self_signed when: self_signed
- name: create nginx bridge network - name: create external bridge network
docker_network: docker_network:
name: nginx-internal name: external
attachable: true attachable: true
internal: true internal: false
state: present state: present
- name: copy nginx.conf - name: copy nginx.conf
template: template:
@ -37,8 +37,7 @@
name: 'nginx' name: 'nginx'
image: nginx image: nginx
networks: networks:
- name: bridge - name: external
- name: nginx-internal
volumes: volumes:
- "{{ data_folder }}/nginx/conf.d:/etc/nginx/conf.d" - "{{ data_folder }}/nginx/conf.d:/etc/nginx/conf.d"
- "{{ data_folder }}/nginx/nginx.conf:/etc/nginx/nginx.conf" - "{{ data_folder }}/nginx/nginx.conf:/etc/nginx/nginx.conf"
@ -53,5 +52,4 @@
env: env:
NGINX_HOST: "{{ base_domain }}" NGINX_HOST: "{{ base_domain }}"
NGINX_PORT: '80' NGINX_PORT: '80'
state: started state: started
restart: yes

View File

@ -13,6 +13,8 @@ events {
http { http {
include /etc/nginx/mime.types; include /etc/nginx/mime.types;
default_type application/octet-stream; default_type application/octet-stream;
log_subrequest on;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" ' '$status $body_bytes_sent "$http_referer" '

View File

@ -6,13 +6,19 @@
loop: loop:
- "{{ data_folder }}/openldap" - "{{ data_folder }}/openldap"
- "{{ data_folder }}/openldap/data" - "{{ data_folder }}/openldap/data"
- name: create network
docker_network:
name: openldap
attachable: true
internal: true
state: present
- name: run container - name: run container
docker_container: docker_container:
name: "openldap" name: "openldap"
image: osixia/openldap image: osixia/openldap
hostname: openldap hostname: openldap
networks: networks:
- name: nginx-internal - name: openldap
ports: ports:
- "389:389" - "389:389"
- "636:636" - "636:636"
@ -23,5 +29,4 @@
LDAP_DOMAIN: "kucharczyk.xyz" LDAP_DOMAIN: "kucharczyk.xyz"
LDAP_ADMIN_PASSWORD: "{{ vault_openldap_admin_password }}" LDAP_ADMIN_PASSWORD: "{{ vault_openldap_admin_password }}"
LDAP_REMOVE_CONFIG_AFTER_SETUP: "false" LDAP_REMOVE_CONFIG_AFTER_SETUP: "false"
state: started state: started
restart: yes

View File

@ -1,6 +0,0 @@
dn: dc=kucharczyk,dc=xyz
objectclass: top
objectclass: dcObject
objectclass: organization
dc: kucharczyk
o: Homelab

View File

@ -0,0 +1,19 @@
- name: run container
docker_container:
name: 'portainer'
image: portainer/portainer-ce
networks:
- name: external
- name: openldap
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
ports:
- "8000:8000"
- "9000:9000"
state: started
- name: copy nginx conf
template:
src: portainer.conf.j2
dest: "{{ data_folder }}/nginx/conf.d/{{ role_name }}.{{ base_domain }}.conf"
mode: "755"
notify: reload nginx

View File

@ -0,0 +1,20 @@
server {
server_name portainer.{{ base_domain }};
listen 80;
return 301 https://$server_name$request_uri;
}
server {
server_name portainer.{{ base_domain }};
listen 443 ssl http2;
include /etc/nginx/snippets/authelia-endpoint.conf;
location / {
include /etc/nginx/snippets/proxy.conf;
include /etc/nginx/snippets/authelia-auth.conf;
set $upstream http://portainer:9000; # This example assumes a Docker deployment
proxy_pass $upstream;
}
}

View File

@ -0,0 +1,34 @@
- name: ensure directories exist
file:
path: "{{ item }}"
state: directory
mode: '0755'
loop:
- "{{ data_folder }}/radarr"
- "{{ media.tv }}"
- "{{ media.movies }}"
- "{{ downloads.nzb }}"
- name: run container
docker_container:
name: "{{ role_name }}"
image: "linuxserver/radarr"
networks:
- name: external
env:
"TZ": "{{ tz }}"
"PUID": "{{ puid }}"
"PGID": "{{ pgid }}"
"UMASK": "022"
volumes:
- "{{ data_folder }}/radarr:/config"
- "{{ downloads.nzb }}:/downloads"
- "{{ media.movies }}:/movies"
ports:
- "7878:7878"
state: started
- name: copy nginx conf
template:
src: "{{ role_name }}.conf.j2"
dest: "{{ data_folder }}/nginx/conf.d/{{ role_name }}.{{ base_domain }}.conf"
mode: "755"
notify: reload nginx

View File

@ -0,0 +1,20 @@
server {
server_name {{ role_name }}.{{ base_domain }};
listen 80;
return 301 https://$server_name$request_uri;
}
server {
server_name {{ role_name }}.{{ base_domain }};
listen 443 ssl http2;
include /etc/nginx/snippets/authelia-endpoint.conf;
location / {
include /etc/nginx/snippets/proxy.conf;
include /etc/nginx/snippets/authelia-auth.conf;
set $upstream http://{{ role_name }}:7878;
proxy_pass $upstream;
}
}

View File

@ -1,19 +1,19 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
30346235333931303864373164626134343138306564323034633139363931653066326263333063 35356537316639386637316365393533643061363734323630393363313237643935666639653963
6532376231363635613930376137326439306437636433370a643535356131363164373764613531 3734376266353938653631323266663139306335646635660a373233663964623335663366333434
36363735323930306338623164636563626334653532386632303936343737363731323166323530 34386136656530386639646234316238326132616131616632346537613963636637393839613661
3439353635343236350a663261636633633033396262333164363062396464366135306135386337 6366326639643632320a386436316165343166366134633464393461653434323934326238313430
37333232376531353332373930306462393634386533636363343736646537666665633262633363 39323439306637306134326635323138616337646336653238636539643538613664303764303661
64373434633963316365306562333765313439366431313234313563376630643931386363383233 39636661353538393532663937396363656664613334383261336664336237356366663334633430
33363665613937366433643133613565646364303362626433396339313535383166326138313139 36356235383930653835393439373737623036613565313131626462363034303062323662663832
61616333333530333761393631323461376536363733323764333631346338393166613531666335 66613833613336646633383835653161386363386136663764653734313763383231626434393864
35373764376434346638356439393964313436366439366363393766643333623165353266386634 63313061346335383933623630396336336561633938613237643238616531343766613734666132
66326434333165663630326332333061626366356363313538393130356365343738363237653565 32306362616131396266656162653563356137383239616464306662643032623438373764306361
63613439373930326165326538386566636466306137636336663736333063613238356137346630 32363133626662633435626232653061373831626563323861626635383039613136303632613335
31643064623563656438613665393332656435636233623265323063366139643937633132656337 61363265316534653033393763646565393330633063323634353932353936303638356433306362
65326137396134333230616262333337373833663439313635663438396461373130396332316331 65383938306637333765383263653939633964613230613835326630313761323561376162646439
66613933343365363335653135663237363538353863623534373563626166313034323039396334 62323035323634323766393233326363383364653531306432663263303831623936616139306639
61383766343264313438353261306233373562343939663232383466336232373865356561316139 64303863386265343165666435363761653464386366636366323261353731643263356635383536
38316466306531326165343265393262646463626563306363353765343462316534323336356432 66326666616339653731633530663161363933383334376238313637356331663431336433643338
34373661363562636137393235323839616430376163393362313363626636343064663739313963 64313861306161373538363332663363623131303561373237326436373838393965306663333835
3361333438346265623738393431346433353436666262396264 3764356534323963303832653964666431626538316361613137