refactor: move all service roles into a single alpina role
This commit is contained in:
12
roles/alpina/collections/apps/arrstack/app_config.yml
Normal file
12
roles/alpina/collections/apps/arrstack/app_config.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
$ANSIBLE_VAULT;1.2;AES256;alpina
|
||||
37653839366635373530306432303538626233356164633761316231623732316138643532383735
|
||||
3132613432333636383363383162643434626638613234320a343337333435393461323735646338
|
||||
34353764366561633738383933626261643734343266333364353162366161313738663064656530
|
||||
6666313731343663650a343761646664356238373763383136366431383337313065613663303233
|
||||
36613233653666306338373839623130323833393932386161353933613338613836326632653262
|
||||
31646131646637646237373964376365336337386639396266393731623761393038396233663663
|
||||
32393964313361326463356435343064643964343731386238643263653738356534383536353330
|
||||
32376162376235663636626562646436613265656461656133643762396137313238383533653831
|
||||
31396632656630626138326335363462383131343431336264656236346665366236353863326237
|
||||
66653064653166373838653631653563303834303334633830383064323965393563663563636361
|
||||
653139663339346331336435313263343936
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
|
||||
local_gateway=$(ip route | grep default | awk '{print $3}')
|
||||
# This used as the gateway address for NAT-PMP to work properly
|
||||
wg_gateway="{{ wg_dns }}"
|
||||
wg_peer_address=$(echo "{{ wg_peer_endpoint }}" | cut -d: -f1)
|
||||
|
||||
ip route add "$wg_peer_address" via "$local_gateway"
|
||||
ip link add wg0 type wireguard
|
||||
wg setconf wg0 /etc/wireguard/wg0.conf
|
||||
ip address add dev wg0 "{{ wg_address }}"
|
||||
ip link set wg0 up
|
||||
ip route add "$wg_gateway" dev wg0
|
||||
ip route del default
|
||||
ip route add default via "$wg_gateway"
|
||||
|
||||
# Note that the DNS isn't changed, so there's actually a leak there
|
||||
# That's on purpose, just in case I want to access local jackett from qbit
|
||||
|
||||
# Still need to figure out how to make this work with IPv6
|
||||
# Prevent IPv6 leaks
|
||||
# ip -6 route del default
|
||||
|
||||
# Finally, optionally allow access to the home network
|
||||
# ip route add "\{\{ home_network }}" via "$local_gateway"
|
||||
@@ -0,0 +1,79 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
{##}
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
{# {{ helpers.default_network(249) | indent(2) }}#}
|
||||
# TODO: Figure out IPv6 leaks
|
||||
ipv4_only:
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
qbittorrent:
|
||||
image: linuxserver/qbittorrent:latest
|
||||
container_name: qbittorrent
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('qbit', port='8080', auth=true) | indent(6) }}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DOCKER_MODS=linuxserver/mods:universal-package-install
|
||||
- INSTALL_PACKAGES=wireguard-tools-wg
|
||||
networks:
|
||||
- ipv4_only
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- ./wireguard:/etc/wireguard:ro
|
||||
- ./custom-init:/custom-cont-init.d:ro
|
||||
- {{ base_volume_path }}/arrstack/config/qbittorrent:/config
|
||||
- {{ base_volume_path }}/arrstack/downloads:/downloads
|
||||
- {{ media_volume_path }}/Plex:/media/Plex
|
||||
- {{ media_volume_path }}/iso-img:/media/iso-img
|
||||
|
||||
prowlarr:
|
||||
image: linuxserver/prowlarr:latest
|
||||
container_name: prowlarr
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('prowlarr', port='9696', auth=true) | indent(6) }}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- qbittorrent
|
||||
networks:
|
||||
- ipv4_only
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/arrstack/config/prowlarr:/config
|
||||
|
||||
sonarr:
|
||||
image: linuxserver/sonarr:latest
|
||||
container_name: sonarr
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('sonarr', port='8989', auth=true) | indent(6) }}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- qbittorrent
|
||||
networks:
|
||||
- ipv4_only
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/arrstack/config/sonarr:/config
|
||||
- {{ base_volume_path }}/arrstack/downloads:/downloads
|
||||
- {{ media_volume_path }}/Plex:/media/Plex
|
||||
|
||||
radarr:
|
||||
image: linuxserver/radarr:latest
|
||||
container_name: radarr
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('radarr', port='7878', auth=true) | indent(6) }}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- qbittorrent
|
||||
networks:
|
||||
- ipv4_only
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/arrstack/config/radarr:/config
|
||||
- {{ base_volume_path }}/arrstack/downloads:/downloads
|
||||
- {{ media_volume_path }}/Plex:/media/Plex
|
||||
@@ -0,0 +1,11 @@
|
||||
# Stripped version of the wg config
|
||||
|
||||
[Interface]
|
||||
PrivateKey = {{ wg_privkey }}
|
||||
# Address = {{ wg_address }}
|
||||
# DNS = {{ wg_dns }} # This is also used as the gateway address for NAT-PMP to work properly
|
||||
|
||||
[Peer]
|
||||
PublicKey = {{ wg_peer_pubkey }}
|
||||
AllowedIPs = 0.0.0.0/0,::0/0
|
||||
Endpoint = {{ wg_peer_endpoint }}
|
||||
27
roles/alpina/collections/apps/gitea/app_config.yml
Normal file
27
roles/alpina/collections/apps/gitea/app_config.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
$ANSIBLE_VAULT;1.2;AES256;alpina
|
||||
35303032386566343430633238343936366234333434343763666231666232633539303232383534
|
||||
3035346233346162373939333531613535353232626531640a646537616163353736653161326265
|
||||
31336530316335623335353661373834613264326436303933326135396166346562343136353931
|
||||
6439383039346465300a366266393130356630316630333336616565366562613038393239623738
|
||||
65626664643630353236333932373337333363626337386163613464306638633964663264363964
|
||||
30373661393531306662323134626664656233323762393037356434353066343830333033316365
|
||||
65616636613437663737306263373066306361376630616331663031346434336663393862316464
|
||||
62343339663461353934323063653566303932656264363562333136353665336263646230323832
|
||||
35376666303531383961646234663230663634393135326664386665633538616233613866373965
|
||||
64363361313232316336376631646662376565353536316438306361306261663532386564616566
|
||||
61663534393035343233326562303863646165346538393761326335376165623964396130393831
|
||||
64333665313461666335383134613831376138393061343238643661366439636534626265323865
|
||||
35393035336632653038623438626366373733626331633866373935616531623664303063376562
|
||||
31356332346164663364636235333461383437623161343338643839323765336237633266633864
|
||||
64363234646533616439313638363865373364623637636537623666383664656630333533303233
|
||||
64383734366666633832393230663739333435666138636462336332373061346239306136336263
|
||||
39643666303863303035313738343664636536663939616335303834333834363739303938646665
|
||||
66303637633239373461393434313036316563313132356432633337666537616363373830313034
|
||||
61313538633663653230643262613333306361666131663036643162343966313365653566393235
|
||||
36623832663034373734653664613038363137366437326565373761663963636336393536386435
|
||||
30393831326134376639366661653439616138643438646363343632346131306532663439396534
|
||||
32383661306539306635336262383563376561303862396532633362666266313562623336383235
|
||||
36366565633734633639653239306331333237353233326563653930653739316230666362323931
|
||||
39663931376562653530323434656436353166393836643238643632396430353034333034333665
|
||||
62323338373839383132323537353431636537616366393965643463316164323034316536383961
|
||||
6164333537633631646663333463306236613038326339643439
|
||||
3
roles/alpina/collections/apps/gitea/templates/.env.db.j2
Normal file
3
roles/alpina/collections/apps/gitea/templates/.env.db.j2
Normal file
@@ -0,0 +1,3 @@
|
||||
POSTGRES_USER=gitea
|
||||
POSTGRES_DB=gitea
|
||||
POSTGRES_PASSWORD={{ db_password }}
|
||||
29
roles/alpina/collections/apps/gitea/templates/.env.gitea.j2
Normal file
29
roles/alpina/collections/apps/gitea/templates/.env.gitea.j2
Normal file
@@ -0,0 +1,29 @@
|
||||
GITEA____APP_NAME=CazGitea
|
||||
|
||||
# Database
|
||||
GITEA__database__DB_TYPE=postgres
|
||||
GITEA__database__HOST=db:5432
|
||||
GITEA__database__NAME={{ db_user }}
|
||||
GITEA__database__USER={{ db_name }}
|
||||
GITEA__database__PASSWD={{ db_password }}
|
||||
|
||||
# Server
|
||||
GITEA__server__ROOT_URL=https://gitea.{{ domain }}/
|
||||
GITEA__server__DISABLE_SSH=true
|
||||
|
||||
# Mail
|
||||
GITEA__mailer__ENABLED=true
|
||||
GITEA__mailer__SMTP_ADDR=smtp.sendgrid.net
|
||||
GITEA__mailer__SMTP_PORT=587
|
||||
GITEA__mailer__FROM=gitea@cazzzer.com
|
||||
GITEA__mailer__USER=apikey
|
||||
GITEA__mailer__PASSWD={{ sendgrid_api_key }}
|
||||
|
||||
# Security
|
||||
GITEA__security__SECRET_KEY={{ secret_key }}
|
||||
GITEA__security__INTERNAL_TOKEN={{ internal_token }}
|
||||
|
||||
GITEA__oauth2__JWT_SECRET={{ jwt_secret }}
|
||||
|
||||
# Indexer
|
||||
GITEA__indexer__REPO_INDEXER_ENABLED=true
|
||||
@@ -0,0 +1,35 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
{##}
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(252) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
server:
|
||||
image: gitea/gitea:1.18
|
||||
container_name: gitea_server
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('gitea', port='3000') | indent(6) }}
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.gitea
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/gitea/gitea:/data
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: postgres:14-alpine
|
||||
container_name: gitea_db
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.db
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- {{ base_volume_path }}/gitea/postgres:/var/lib/postgresql/data
|
||||
6
roles/alpina/collections/apps/jellyfin/app_config.yml
Normal file
6
roles/alpina/collections/apps/jellyfin/app_config.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
$ANSIBLE_VAULT;1.2;AES256;alpina
|
||||
61626665353536663033663661393434616339396434383530306265363837313839303939623465
|
||||
3634333839333530383464613966326238363738663637360a343837623832343232316565346131
|
||||
66663831356162653363383131396665326531363430656539333866313031306537343864343262
|
||||
3730643765633232620a643734623336646565663266656262343162613239306166386665333139
|
||||
6366
|
||||
@@ -0,0 +1 @@
|
||||
JELLYFIN_PublishedServerUrl=https://jellyfin.{{ domain }}
|
||||
@@ -0,0 +1,30 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
{##}
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(250) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:10.8.6
|
||||
container_name: jellyfin_jellyfin
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('jellyfin', port='8096') | indent(6) }}
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.jellyfin
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
volumes:
|
||||
- {{ base_volume_path }}/jellyfin/config:/config
|
||||
- {{ base_volume_path }}/jellyfin/cache:/cache
|
||||
- {{ media_volume_path }}/Plex/media:/data/media:ro
|
||||
- {{ media_volume_path }}/other_videos:/data/other_videos:ro
|
||||
tmpfs:
|
||||
- /tmp/transcodes
|
||||
devices:
|
||||
- /dev/dri:/dev/dri
|
||||
14
roles/alpina/collections/apps/nextcloud/app_config.yml
Normal file
14
roles/alpina/collections/apps/nextcloud/app_config.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
$ANSIBLE_VAULT;1.2;AES256;alpina
|
||||
65313636646233613364363933616361346639653939346337303832646339316632383966666237
|
||||
3766396134383434613534373937663162393134306536300a626139373732393037346630333838
|
||||
63663439353238643532316231623866396434303034313130386635623363353263626362376334
|
||||
3933346434633662320a386432373465646432343338666561366161646335636232353133393933
|
||||
65313364666564353039626238383033343765323730316633356139326666623135326131353864
|
||||
32386237643538636538356261393164633137636235346564393930346539623731386633336339
|
||||
31303466653936343166366164383134306232613236663735623834393963306331376435616365
|
||||
31313866383730393063353335626164303632636331303830636530656131636139376633623439
|
||||
63663639323964623231343066373538633336353561646230363363643762393634643435306164
|
||||
31366364326237636365336363343264343562353337303235633034383635373934376334353336
|
||||
61373065386639643064303431623162373665363937353832313561386134613834613935653964
|
||||
64656339316165313936333736643030356366663162316462636662326134396539356262666536
|
||||
64336133393937396330353234316563356337623733326264363333373536633833
|
||||
@@ -0,0 +1,3 @@
|
||||
POSTGRES_USER=nextcloud
|
||||
POSTGRES_DB=nextcloud
|
||||
POSTGRES_PASSWORD={{ db_password }}
|
||||
@@ -0,0 +1 @@
|
||||
NEXTCLOUD_VERSION=25-fpm-alpine
|
||||
@@ -0,0 +1,23 @@
|
||||
POSTGRES_DB=nextcloud
|
||||
POSTGRES_USER=nextcloud
|
||||
POSTGRES_PASSWORD={{ db_password }}
|
||||
POSTGRES_HOST=db
|
||||
|
||||
NEXTCLOUD_TRUSTED_DOMAINS=nc.{{ domain }}
|
||||
|
||||
REDIS_HOST=redis
|
||||
REDIS_HOST_PASSWORD={{ redis_password }}
|
||||
|
||||
SMTP_HOST=smtp.sendgrid.net
|
||||
SMTP_SECURE=tls
|
||||
SMTP_PORT=587
|
||||
SMTP_AUTHTYPE=LOGIN
|
||||
SMTP_NAME=apikey
|
||||
SMTP_PASSWORD={{ sendgrid_api_key }}
|
||||
MAIL_FROM_ADDRESS=nc
|
||||
MAIL_DOMAIN=cazzzer.com
|
||||
|
||||
TRUSTED_PROXIES={{ traefik_ip }}
|
||||
OVERWRITEHOST=nc.{{ domain }}
|
||||
OVERWRITEPROTOCOL=https
|
||||
OVERWRITECLIURL=https://nc.{{ domain }}
|
||||
@@ -0,0 +1 @@
|
||||
REDIS_PASSWORD={{ redis_password }}
|
||||
@@ -0,0 +1,97 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
{##}
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(251) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
|
||||
services:
|
||||
app:
|
||||
image: nextcloud:${NEXTCLOUD_VERSION}
|
||||
container_name: nextcloud_app
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
env_file:
|
||||
- .env.nextcloud
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud:/var/www/html
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_config:/var/www/html/config
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_data:/var/www/html/data
|
||||
|
||||
cron:
|
||||
image: nextcloud:${NEXTCLOUD_VERSION}
|
||||
container_name: nextcloud_cron
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- app
|
||||
entrypoint: /cron.sh
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud:/var/www/html
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_config:/var/www/html/config
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_data:/var/www/html/data
|
||||
|
||||
notify_push:
|
||||
image: nextcloud:${NEXTCLOUD_VERSION}
|
||||
container_name: nextcloud_notify_push
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- app
|
||||
entrypoint:
|
||||
- /var/www/html/custom_apps/notify_push/bin/x86_64/notify_push
|
||||
- /var/www/html/config/config.php
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud:/var/www/html
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_config:/var/www/html/config
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_data:/var/www/html/data
|
||||
|
||||
db:
|
||||
image: postgres:13-alpine
|
||||
container_name: nextcloud_db
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.db
|
||||
networks:
|
||||
- default
|
||||
volumes:
|
||||
- {{ base_volume_path }}/nextcloud/db:/var/lib/postgresql/data
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: nextcloud_redis
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.redis
|
||||
networks:
|
||||
- default
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- redis-server --requirepass $$REDIS_PASSWORD
|
||||
|
||||
web:
|
||||
image: nginx:1.23-alpine
|
||||
container_name: nextcloud_web
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('nc') | indent(6) }}
|
||||
restart: unless-stopped
|
||||
links:
|
||||
- app
|
||||
networks:
|
||||
- traefik_traefik
|
||||
- default
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud:/var/www/html
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_config:/var/www/html/config
|
||||
- {{ base_volume_path }}/nextcloud/nextcloud_data:/var/www/html/data
|
||||
182
roles/alpina/collections/apps/nextcloud/templates/nginx.conf.j2
Normal file
182
roles/alpina/collections/apps/nextcloud/templates/nginx.conf.j2
Normal file
@@ -0,0 +1,182 @@
|
||||
# https://github.com/nextcloud/docker/blob/master/.examples/docker-compose/with-nginx-proxy/postgres/fpm/web/nginx.conf
|
||||
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
# Prevent nginx HTTP Server Detection
|
||||
server_tokens off;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
upstream php-handler {
|
||||
server app:9000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
# HSTS settings
|
||||
# WARNING: Only add the preload option once you read about
|
||||
# the consequences in https://hstspreload.org/. This option
|
||||
# will add the domain to a hardcoded list that is shipped
|
||||
# in all major browsers and getting removed from this list
|
||||
# could take several months.
|
||||
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
|
||||
|
||||
# set max upload size
|
||||
client_max_body_size 512M;
|
||||
fastcgi_buffers 64 4K;
|
||||
|
||||
# Enable gzip but do not remove ETag headers
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_comp_level 4;
|
||||
gzip_min_length 256;
|
||||
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
|
||||
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
|
||||
|
||||
# Pagespeed is not supported by Nextcloud, so if your server is built
|
||||
# with the `ngx_pagespeed` module, uncomment this line to disable it.
|
||||
#pagespeed off;
|
||||
|
||||
# HTTP response headers borrowed from Nextcloud `.htaccess`
|
||||
add_header Referrer-Policy "no-referrer" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Download-Options "noopen" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Permitted-Cross-Domain-Policies "none" always;
|
||||
add_header X-Robots-Tag "none" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Remove X-Powered-By, which is an information leak
|
||||
fastcgi_hide_header X-Powered-By;
|
||||
|
||||
# Path to the root of your installation
|
||||
root /var/www/html;
|
||||
|
||||
# Specify how to handle directories -- specifying `/index.php$request_uri`
|
||||
# here as the fallback means that Nginx always exhibits the desired behaviour
|
||||
# when a client requests a path that corresponds to a directory that exists
|
||||
# on the server. In particular, if that directory contains an index.php file,
|
||||
# that file is correctly served; if it doesn't, then the request is passed to
|
||||
# the front-end controller. This consistent behaviour means that we don't need
|
||||
# to specify custom rules for certain paths (e.g. images and other assets,
|
||||
# `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
|
||||
# `try_files $uri $uri/ /index.php$request_uri`
|
||||
# always provides the desired behaviour.
|
||||
index index.php index.html /index.php$request_uri;
|
||||
|
||||
# Rule borrowed from `.htaccess` to handle Microsoft DAV clients
|
||||
location = / {
|
||||
if ( $http_user_agent ~ ^DavClnt ) {
|
||||
return 302 /remote.php/webdav/$is_args$args;
|
||||
}
|
||||
}
|
||||
|
||||
location = /robots.txt {
|
||||
allow all;
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Make a regex exception for `/.well-known` so that clients can still
|
||||
# access it despite the existence of the regex rule
|
||||
# `location ~ /(\.|autotest|...)` which would otherwise handle requests
|
||||
# for `/.well-known`.
|
||||
location ^~ /.well-known {
|
||||
# The rules in this block are an adaptation of the rules
|
||||
# in `.htaccess` that concern `/.well-known`.
|
||||
|
||||
location = /.well-known/carddav { return 301 /remote.php/dav/; }
|
||||
location = /.well-known/caldav { return 301 /remote.php/dav/; }
|
||||
|
||||
location /.well-known/acme-challenge { try_files $uri $uri/ =404; }
|
||||
location /.well-known/pki-validation { try_files $uri $uri/ =404; }
|
||||
|
||||
# Let Nextcloud's API for `/.well-known` URIs handle all other
|
||||
# requests by passing them to the front-end controller.
|
||||
return 301 /index.php$request_uri;
|
||||
}
|
||||
|
||||
# Rules borrowed from `.htaccess` to hide certain paths from clients
|
||||
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
|
||||
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
|
||||
|
||||
# Ensure this block, which passes PHP files to the PHP process, is above the blocks
|
||||
# which handle static assets (as seen below). If this block is not declared first,
|
||||
# then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
|
||||
# to the URI, resulting in a HTTP 500 error response.
|
||||
location ~ \.php(?:$|/) {
|
||||
# Required for legacy support
|
||||
rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;
|
||||
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
set $path_info $fastcgi_path_info;
|
||||
|
||||
try_files $fastcgi_script_name =404;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $path_info;
|
||||
#fastcgi_param HTTPS on;
|
||||
|
||||
fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice
|
||||
fastcgi_param front_controller_active true; # Enable pretty urls
|
||||
fastcgi_pass php-handler;
|
||||
|
||||
fastcgi_intercept_errors on;
|
||||
fastcgi_request_buffering off;
|
||||
}
|
||||
|
||||
location ~ \.(?:css|js|svg|gif)$ {
|
||||
try_files $uri /index.php$request_uri;
|
||||
expires 6M; # Cache-Control policy borrowed from `.htaccess`
|
||||
access_log off; # Optional: Don't log access to assets
|
||||
}
|
||||
|
||||
location ~ \.woff2?$ {
|
||||
try_files $uri /index.php$request_uri;
|
||||
expires 7d; # Cache-Control policy borrowed from `.htaccess`
|
||||
access_log off; # Optional: Don't log access to assets
|
||||
}
|
||||
|
||||
# Rule borrowed from `.htaccess`
|
||||
location /remote {
|
||||
return 301 /remote.php$request_uri;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php$request_uri;
|
||||
}
|
||||
|
||||
location ^~ /push/ {
|
||||
proxy_pass http://notify_push:7867/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
roles/alpina/collections/services/authentik/app_config.yml
Normal file
19
roles/alpina/collections/services/authentik/app_config.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
$ANSIBLE_VAULT;1.2;AES256;alpina
|
||||
33343634343761393265346336326263346166326365656461353361373738343262613534363664
|
||||
6238313838623436643730393465353361343730343938380a373235363835313561333934366361
|
||||
61626630616365633134393337376464303537623839623639626561383036663432336537396338
|
||||
6230366561373638350a636634613436346237373166626162656535306234346439666161633634
|
||||
63633436376562373739396261313133383161353463393737346436623239346232393034363335
|
||||
38363962306463386464633338363162623832363431373765656232343931376363653464313438
|
||||
62316635623236633762353061326539343435393737333563313331393134643439393463623637
|
||||
64633262656366333537663663346239653533353132343066383438333636396238393135623530
|
||||
35323439666437313936343733376336383961653864396133373831316139353163613337306533
|
||||
63366233333865653166336466343830336239346532373466376261333530666230633434393933
|
||||
30383032613466393833353065653465633633663333663132636164303264316163343961653562
|
||||
36356138343130316636333231613033646565353863323132643432656239636538366462353338
|
||||
37353936326661303064313635633865663939316631623764393235383630353132343135616338
|
||||
32623938616136326561323033336134636364623165646566646662353066623432363538386364
|
||||
30663734366136313933666332323538346266306133383838323839363233653435643862316136
|
||||
33353436313834356230313164623838363363336266323637353263353763326235636161383836
|
||||
63323839363438333538326130653063313734303237623234376235396638343531623661626661
|
||||
3364616438373366663837613933376361653664363532653833
|
||||
@@ -0,0 +1,21 @@
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED=true
|
||||
|
||||
AUTHENTIK_REDIS__HOST=redis
|
||||
AUTHENTIK_POSTGRESQL__HOST=postgres
|
||||
AUTHENTIK_POSTGRESQL__USER=authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME=authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD={{ db_password }}
|
||||
|
||||
AUTHENTIK_SECRET_KEY={{ authentik_secret_key }}
|
||||
|
||||
AUTHENTIK_EMAIL__HOST=smtp.sendgrid.net
|
||||
AUTHENTIK_EMAIL__PORT=587
|
||||
AUTHENTIK_EMAIL__USERNAME=apikey
|
||||
AUTHENTIK_EMAIL__PASSWORD={{ sengrid_api_key }}
|
||||
|
||||
AUTHENTIK_EMAIL__USE_TLS=true
|
||||
AUTHENTIK_EMAIL__TIMEOUT=10
|
||||
AUTHENTIK_EMAIL__FROM=auth@cazzzer.com
|
||||
|
||||
AUTHENTIK_DEFAULT_USER_CHANGE_EMAIL=false
|
||||
AUTHENTIK_DEFAULT_USER_CHANGE_USERNAME=false
|
||||
@@ -0,0 +1,3 @@
|
||||
POSTGRES_USER=authentik
|
||||
POSTGRES_DB=authentik
|
||||
POSTGRES_PASSWORD={{ db_password }}
|
||||
@@ -0,0 +1 @@
|
||||
AUTHENTIK_VERSION=2023.3
|
||||
@@ -0,0 +1,51 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
name: Alpina - OAuth2 Apps
|
||||
entries:
|
||||
{% set apps = {
|
||||
"Gitea": {
|
||||
"redirect_uris": "https://gitea."~ domain ~"/user/oauth2/Authentik/callback",
|
||||
"icon": "https://gitea."~ domain ~"/assets/img/logo.svg",
|
||||
},
|
||||
"Nextcloud": {
|
||||
"redirect_uris": "https://nc."~ domain ~"/apps/sociallogin/custom_oidc/authentik",
|
||||
"icon": "https://nc."~ domain ~"/apps/theming/favicon",
|
||||
},
|
||||
} -%}
|
||||
{% for app in apps.keys() -%}
|
||||
- identifiers:
|
||||
name: {{ app }}
|
||||
model: authentik_providers_oauth2.oauth2provider
|
||||
id: {{ app | lower }}
|
||||
attrs:
|
||||
access_code_validity: minutes=1
|
||||
access_token_validity: minutes=5
|
||||
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
|
||||
client_type: confidential
|
||||
issuer_mode: per_provider
|
||||
sub_mode: hashed_user_id
|
||||
property_mappings:
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]]
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]]
|
||||
redirect_uris: {{ apps[app]["redirect_uris"] }}
|
||||
refresh_token_validity: days=30
|
||||
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]]
|
||||
|
||||
- identifiers:
|
||||
slug: {{ app | lower }}
|
||||
model: authentik_core.application
|
||||
id: {{ app | lower }}
|
||||
attrs:
|
||||
name: {{ app }}
|
||||
group: "Apps"
|
||||
meta_description: "Hello, I'm {{ app }}!"
|
||||
meta_publisher: Alpina
|
||||
# This isn't supported yet, https://github.com/goauthentik/authentik/issues/3484
|
||||
# meta_icon: "{{ apps[app]["icon"] }}"
|
||||
open_in_new_tab: true
|
||||
policy_engine_mode: any
|
||||
provider: !KeyOf {{ app | lower }}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,73 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
name: Alpina - Arrstack Proxy
|
||||
entries:
|
||||
- identifiers:
|
||||
name: arrstack
|
||||
model: authentik_core.group
|
||||
id: arrstack
|
||||
attrs:
|
||||
arrstack_username: "arr"
|
||||
arrstack_password: "{{ arrstack_password }}"
|
||||
|
||||
{% for service in ["qBit", "Prowlarr", "Sonarr", "Radarr"] -%}
|
||||
- identifiers:
|
||||
name: {{ service }}
|
||||
model: authentik_providers_proxy.proxyprovider
|
||||
id: {{ service | lower }}
|
||||
attrs:
|
||||
access_token_validity: hours=24
|
||||
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
|
||||
certificate: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]]
|
||||
{% if service != 'qBit' -%}
|
||||
basic_auth_enabled: true
|
||||
basic_auth_user_attribute: arrstack_username
|
||||
basic_auth_password_attribute: arrstack_password
|
||||
{% endif -%}
|
||||
intercept_header_auth: true
|
||||
external_host: https://{{ service | lower }}.{{ domain }}/
|
||||
mode: forward_single
|
||||
property_mappings:
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]]
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]]
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, ak_proxy]]
|
||||
refresh_token_validity: days=30
|
||||
skip_path_regex: {{ "/images/qbittorrent-tray.svg" if service == "qBit" else "/Content/Images/logo.svg" }}
|
||||
|
||||
- identifiers:
|
||||
slug: {{ service | lower }}
|
||||
model: authentik_core.application
|
||||
id: {{ service | lower }}
|
||||
attrs:
|
||||
name: {{ service }}
|
||||
group: "Arrstack"
|
||||
meta_description: "Hello, I'm {{ service }}!"
|
||||
meta_publisher: Alpina
|
||||
# This isn't supported yet, https://github.com/goauthentik/authentik/issues/3484
|
||||
# meta_icon: "https://{{ service }}.{{ domain }}/Content/Images/logo.svg"
|
||||
open_in_new_tab: true
|
||||
policy_engine_mode: any
|
||||
provider: !KeyOf {{ service | lower }}
|
||||
|
||||
- identifiers:
|
||||
group: !KeyOf arrstack
|
||||
target: !Find [authentik_core.application, [slug, {{ service | lower }}]]
|
||||
model: authentik_policies.policybinding
|
||||
attrs:
|
||||
enabled: true
|
||||
order: 0
|
||||
timeout: 30
|
||||
{% endfor %}
|
||||
|
||||
- identifiers:
|
||||
managed: goauthentik.io/outposts/embedded
|
||||
name: authentik Embedded Outpost
|
||||
model: authentik_outposts.outpost
|
||||
attrs:
|
||||
providers:
|
||||
{% for service in ["qBit", "Prowlarr", "Sonarr", "Radarr"] -%}
|
||||
- !KeyOf {{ service | lower }}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,19 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
name: Alpina - Default Identification Stage
|
||||
entries:
|
||||
- identifiers:
|
||||
name: default-authentication-identification
|
||||
model: authentik_stages_identification.identificationstage
|
||||
attrs:
|
||||
sources:
|
||||
- !Find [authentik_core.source, [slug, authentik-built-in]]
|
||||
- !Find [authentik_sources_oauth.oauthsource, [slug, github]]
|
||||
|
||||
- identifiers:
|
||||
slug: default-authentication-flow
|
||||
model: authentik_flows.flow
|
||||
attrs:
|
||||
compatibility_mode: true
|
||||
@@ -0,0 +1,25 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
name: Alpina - GitHub OAuth
|
||||
entries:
|
||||
- identifiers:
|
||||
slug: github
|
||||
model: authentik_sources_oauth.oauthsource
|
||||
attrs:
|
||||
name: GitHub
|
||||
slug: github
|
||||
access_token_url: https://github.com/login/oauth/access_token
|
||||
additional_scopes: openid read:org
|
||||
authentication_flow: !Find [authentik_flows.flow, [slug, default-source-authentication]]
|
||||
authorization_url: https://github.com/login/oauth/authorize
|
||||
consumer_key: {{ github_consumer_key }}
|
||||
consumer_secret: {{ github_consumer_secret }}
|
||||
enabled: true
|
||||
enrollment_flow: !Find [authentik_flows.flow, [slug, default-source-enrollment]]
|
||||
policy_engine_mode: any
|
||||
profile_url: https://api.github.com/user
|
||||
provider_type: github
|
||||
user_matching_mode: email_link
|
||||
user_path_template: goauthentik.io/sources/%(slug)s
|
||||
@@ -0,0 +1,68 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
{##}
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
{{ helpers.default_network(253) | indent(2) }}
|
||||
traefik_traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
server:
|
||||
image: ghcr.io/goauthentik/server:${AUTHENTIK_VERSION}
|
||||
container_name: authentik_server
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('auth', port='9000') | indent(6) }}
|
||||
- traefik.http.middlewares.authentik.forwardauth.address=http://localhost:9000/outpost.goauthentik.io/auth/traefik
|
||||
- traefik.http.middlewares.authentik.forwardauth.trustForwardHeader=true
|
||||
- traefik.http.middlewares.authentik.forwardauth.authResponseHeaders=Authorization,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version
|
||||
restart: unless-stopped
|
||||
# Port forward is needed because traefik can't resolve the container name from the host network
|
||||
ports:
|
||||
- "9000:9000"
|
||||
command: server
|
||||
env_file:
|
||||
- .env.authentik
|
||||
networks:
|
||||
- default
|
||||
- traefik_traefik
|
||||
|
||||
worker:
|
||||
image: ghcr.io/goauthentik/server:${AUTHENTIK_VERSION}
|
||||
container_name: authentik_worker
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
env_file:
|
||||
- .env.authentik
|
||||
volumes:
|
||||
- ./blueprints:/blueprints/alpina
|
||||
- {{ base_volume_path }}/authentik/certs:/certs
|
||||
|
||||
postgres:
|
||||
image: postgres:12-alpine
|
||||
container_name: authentik_postgres
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.db
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 5s
|
||||
volumes:
|
||||
- {{ base_volume_path }}/authentik/postgres:/var/lib/postgresql/data
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
container_name: authentik_redis
|
||||
restart: unless-stopped
|
||||
command: --save 60 1 --loglevel warning
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 3s
|
||||
volumes:
|
||||
- {{ base_volume_path }}/authentik/redis:/data
|
||||
10
roles/alpina/collections/services/traefik/app_config.yml
Normal file
10
roles/alpina/collections/services/traefik/app_config.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
$ANSIBLE_VAULT;1.2;AES256;alpina
|
||||
35326636356536326332383464373937366130613966663736396135306131353463353334336364
|
||||
6438346563313332313835326634383063323739643165660a353431336266353239323863363637
|
||||
34383565626131353530313531663034386530373133653463353063626466613436366235393638
|
||||
6432363033343336620a336265666362663861393762316137356635363834326566623462373531
|
||||
62313233306533336331383964346536303362383639633337386664646535313133633164316530
|
||||
62623535633062656330363931353665396431376233613936626232313264376634646237303236
|
||||
38396234323931613539393034396461383564363064356635343730633233366666313434646439
|
||||
34633739333964383865396133313936363166643464613132633031663065623664616365656164
|
||||
62643035623261623435336462643864396135323139336662363865306661356534
|
||||
@@ -0,0 +1 @@
|
||||
CF_DNS_API_TOKEN={{ cloudflare_api_token }}
|
||||
@@ -0,0 +1,37 @@
|
||||
{% import 'contrib/compose_helpers.j2' as helpers with context %}
|
||||
{##}
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
internal: true
|
||||
enable_ipv6: true
|
||||
ipam:
|
||||
config:
|
||||
- subnet: {{ traefik_ip }}/24
|
||||
- subnet: {{ docker_ipv6_subnet | ansible.utils.ipsubnet(80, 255) }}
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v2.9
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.traefik
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./traefik.yml:/etc/traefik/traefik.yml:ro
|
||||
- ./rules:/rules:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- {{ base_volume_path }}/traefik/rules:/rules/extra:ro
|
||||
- {{ base_volume_path }}/traefik/logs:/logs
|
||||
- {{ base_volume_path }}/traefik/acme:/acme
|
||||
|
||||
# This is mostly just so that the traefik network gets created
|
||||
whoami:
|
||||
image: containous/whoami
|
||||
container_name: whoami
|
||||
labels:
|
||||
- {{ helpers.traefik_labels('whoami', port=80) | indent(6) }}
|
||||
networks:
|
||||
- traefik
|
||||
@@ -0,0 +1,25 @@
|
||||
http:
|
||||
routers:
|
||||
traefik-dash:
|
||||
rule: "Host(`traefik.{{ domain }}`)"
|
||||
entryPoints:
|
||||
- web
|
||||
service: traefik-dash
|
||||
|
||||
traefik-dash-tls:
|
||||
rule: "Host(`traefik.{{ domain }}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: traefik-dash
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
domains:
|
||||
- main: "{{ domain }}"
|
||||
sans:
|
||||
- "*.{{ domain }}"
|
||||
|
||||
services:
|
||||
traefik-dash:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://localhost:8080"
|
||||
@@ -0,0 +1,42 @@
|
||||
api:
|
||||
insecure: true
|
||||
|
||||
log:
|
||||
filePath: /logs/traefik.log
|
||||
level: INFO
|
||||
accessLog:
|
||||
filePath: /logs/access.log
|
||||
bufferingSize: 100
|
||||
|
||||
experimental:
|
||||
http3: true
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
websecure:
|
||||
address: ":443"
|
||||
http3:
|
||||
advertisedPort: 443
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: {{ acme_email }}
|
||||
storage: "/acme/acme.json"
|
||||
keyType: "EC384"
|
||||
dnsChallenge:
|
||||
provider: "cloudflare"
|
||||
delayBeforeCheck: 10
|
||||
resolvers:
|
||||
- 1.1.1.1
|
||||
- 8.8.8.8
|
||||
- 9.9.9.9
|
||||
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false
|
||||
network: traefik_traefik
|
||||
file:
|
||||
directory: /rules
|
||||
watch: true
|
||||
18
roles/alpina/tasks/deploy_collection.yml
Normal file
18
roles/alpina/tasks/deploy_collection.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
- name: Ensure {{ collection }} collection directory exists
|
||||
file:
|
||||
path: "{{ my_svc_path }}/{{ collection }}"
|
||||
state: directory
|
||||
mode: "700"
|
||||
|
||||
- name: Deploy docker compose stacks for {{ collection }}
|
||||
vars:
|
||||
current_stack_name: "{{ stack }}"
|
||||
current_stack_dest: "{{ my_svc_path }}/{{ collection }}/{{ stack }}"
|
||||
current_stack_source: "{{ role_path }}/collections/{{ collection }}/{{ stack }}"
|
||||
include_tasks: deploy_compose_stack.yml
|
||||
loop: "{{ stacks }}"
|
||||
loop_control:
|
||||
loop_var: stack
|
||||
|
||||
- debug:
|
||||
var: acme_email
|
||||
40
roles/alpina/tasks/deploy_compose_stack.yml
Normal file
40
roles/alpina/tasks/deploy_compose_stack.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
# https://stackoverflow.com/questions/41667864/can-the-templates-module-handle-multiple-templates-directories
|
||||
|
||||
- name: Ensure stack directory exists
|
||||
file:
|
||||
path: "{{ current_stack_dest }}"
|
||||
state: directory
|
||||
mode: "700"
|
||||
|
||||
- name: Ensure directory structure exists
|
||||
file:
|
||||
path: "{{ current_stack_dest }}/{{ item.path }}"
|
||||
state: directory
|
||||
mode: "700"
|
||||
with_community.general.filetree: "{{ current_stack_source }}/templates"
|
||||
when: item.state == "directory"
|
||||
|
||||
# TODO: This is not ideal as it leaks the variables between stacks
|
||||
# But that's also not really a problem, as they won't conflict if everything is done right
|
||||
- name: Include variables for stack {{ stack }}
|
||||
include_vars:
|
||||
file: "{{ current_stack_source }}/app_config.yml"
|
||||
|
||||
- name: Generate {{ current_stack_name }} deployment from templates
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ current_stack_dest }}/{{ item.path | regex_replace('\\.j2$', '') }}"
|
||||
mode: "600"
|
||||
with_community.general.filetree: "{{ current_stack_source }}/templates"
|
||||
when: item.state == "file"
|
||||
|
||||
- name: Deploy docker-compose for {{ current_stack_name }}
|
||||
command: docker compose -f "{{ current_stack_dest }}/docker-compose.yml" up -d --pull --remove-orphans
|
||||
register: docker_compose_output
|
||||
# Not perfect idempotency, but the built-in docker_compose module doesn't support docker-compose v2
|
||||
# And of course there's an IPv6 bug in docker-compose v1, smh
|
||||
# https://github.com/docker/compose/issues/7670
|
||||
changed_when: "'created' in docker_compose_output.stderr.lower()"
|
||||
|
||||
- debug:
|
||||
var: docker_compose_output
|
||||
23
roles/alpina/tasks/main.yml
Normal file
23
roles/alpina/tasks/main.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
- name: Ensure alpina directory exists
|
||||
file:
|
||||
state: directory
|
||||
path: "{{ my_svc_path }}"
|
||||
mode: "700"
|
||||
|
||||
- name: Deploy collection services
|
||||
vars:
|
||||
collection: services
|
||||
stacks:
|
||||
- traefik
|
||||
- authentik
|
||||
import_tasks: deploy_collection.yml
|
||||
|
||||
- name: Deploy collection apps
|
||||
vars:
|
||||
collection: apps
|
||||
stacks:
|
||||
- gitea
|
||||
- nextcloud
|
||||
- jellyfin
|
||||
- arrstack
|
||||
import_tasks: deploy_collection.yml
|
||||
Reference in New Issue
Block a user