dev #1

Merged
kevinheyer merged 19 commits from dev into main 2025-06-15 07:37:36 +00:00
64 changed files with 763 additions and 3 deletions

2
.ansible-lint Normal file
View file

@ -0,0 +1,2 @@
skip_list:
- var-naming

4
.gitignore vendored
View file

@ -10,3 +10,7 @@ cache/
# Ignore Testplaybook
playbooks/global/testserver.yml
# Ignore unneccessary Files
.vscode
.ansible

View file

@ -2,6 +2,7 @@
inventory = ./inventory/
host_key_checking = False
retry_files_enabled = False
private_key_file = ~/.ssh/ansible_key
# Caching-Einstellungen
gathering = smart
@ -10,7 +11,7 @@ fact_caching_connection = ./cache
fact_caching_timeout = 86400
# Rollen-Pfade
roles_path = ./roles/global:./roles/custom
roles_path = ./roles/
# Vault-Einstellungen
vault_password_file = ./vault.secret

View file

@ -0,0 +1,5 @@
---
- name: Configure all servers
hosts: all
roles:
- server_install_ssh

View file

@ -0,0 +1,7 @@
---
- name: Configure calibre
hosts: calibre
roles:
- server_install_ssh
- server_install_fail2ban
- server_install_syslog

View file

@ -0,0 +1,28 @@
---
- name: Configure docker1
hosts: docker1
roles:
- role: server_install_ssh
tags:
- ssh
- system
- role: server_install_fail2ban
tags:
- fail2ban
- system
- role: server_install_syslog
tags:
- syslog
- system
- role: deploy_container_traefik
tags:
- traefik
- docker-container
- role: deploy_container_homepage
tags:
- homepage
- docker-container

View file

@ -0,0 +1,7 @@
---
- name: Configure Gaming Server
hosts: minecraft
roles:
- server_install_ssh
- server_install_fail2ban
- server_install_syslog

View file

@ -0,0 +1,7 @@
---
- name: Configure pihole
hosts: pihole
roles:
- server_install_ssh
- server_install_fail2ban
- server_install_syslog

View file

@ -0,0 +1,6 @@
---
- name: Configure pve1
hosts: pve1
roles:
- server_install_ssh
- server_install_fail2ban

View file

@ -0,0 +1,6 @@
---
- name: Configure pve2
hosts: pve2
roles:
- server_install_ssh
- server_install_fail2ban

View file

@ -0,0 +1,6 @@
---
- name: Configure pve3
hosts: pve3
roles:
- server_install_ssh
- server_install_fail2ban

View file

@ -0,0 +1,112 @@
Hier ist ein passendes **README.md**, das deine Anforderungen erfüllt:
---
# 📦 Ansible Role: Container Homepage
This role deploys a tenant-specific instance of the **homepage container** (e.g. [gethomepage.dev](https://gethomepage.dev))
It uses Docker Compose and copies custom configuration files per host.
---
## 🚀 **Getting Started**
### 1⃣ **Prepare tenant-specific config files**
All example config files are located in:
```
roles/container_homepage/files/
```
👉 Copy these files to your inventory directory under the following structure:
```
inventory/[TENANT]/host_files/[HOST]/container_homepage_config_files/
```
Example:
```
inventory/tenant1/host_files/docker1/container_homepage_config_files/bookmarks.yaml
inventory/tenant1/host_files/docker1/container_homepage_config_files/settings.yaml
...
```
⚠️ **Customize these files** before deploying, according to the requirements of your tenant and host.
---
## ⚙️ **Default Variables**
These are defined in `defaults/main.yml`:
```yaml
container_homepage_version: latest
container_homepage_domain: dashboard.example.com
container_homepage_directory: /opt/docker/homepage
container_homepage_config_files:
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/bookmarks.yaml"
dest: "bookmarks.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/settings.yaml"
dest: "settings.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/custom.css"
dest: "custom.css"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/custom.js"
dest: "custom.js"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/docker.yaml"
dest: "docker.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/kubernetes.yaml"
dest: "kubernetes.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/services.yaml"
dest: "services.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/widgets.yaml"
dest: "widgets.yaml"
```
---
## 📂 **Inventory example**
```
inventory/
└── tenant1/
├── hosts.yml
└── host_files/
└── docker1/
└── container_homepage_config_files/
├── bookmarks.yaml
├── settings.yaml
├── custom.css
├── custom.js
├── docker.yaml
├── kubernetes.yaml
├── services.yaml
└── widgets.yaml
```
---
## 📝 **Usage**
Run your playbook as usual:
```bash
ansible-playbook -i inventory/tenant1/inventory.yml playbooks/playbook.yml
```
The role will:
✅ Ensure directories exist
✅ Deploy Docker Compose and environment files
✅ Copy the tenant-specific configuration files
✅ Start or update the container
---
## 💡 Notes
* The role expects Docker (with compose v2 plugin) to be installed on the target host.
* The docker-compose and .env files should be templated or provided by your playbook or role.
* Make sure the `container_homepage_directory` location has correct permissions for your user/container runtime.
---

View file

@ -0,0 +1,20 @@
container_homepage_version: latest
container_homepage_domain: dashboard.example.com
container_homepage_directory: /opt/docker/homepage
container_homepage_config_files:
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/bookmarks.yaml"
dest: "bookmarks.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/settings.yaml"
dest: "settings.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/custom.css"
dest: "custom.css"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/custom.js"
dest: "custom.js"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/docker.yaml"
dest: "docker.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/kubernetes.yaml"
dest: "kubernetes.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/services.yaml"
dest: "services.yaml"
- src: "{{ inventory_dir }}/host_files/{{ inventory_hostname }}/container_homepage_config_files/widgets.yaml"
dest: "widgets.yaml"

View file

@ -0,0 +1,18 @@
---
# For configuration options and examples, please see:
# https://gethomepage.dev/configs/bookmarks
- Developer:
- Github:
- abbr: GH
href: https://github.com/
- Social:
- Reddit:
- abbr: RE
href: https://reddit.com/
- Entertainment:
- YouTube:
- abbr: YT
href: https://youtube.com/

View file

@ -0,0 +1,10 @@
---
# For configuration options and examples, please see:
# https://gethomepage.dev/configs/docker/
# my-docker:
# host: 127.0.0.1
# port: 2375
# my-docker:
# socket: /var/run/docker.sock

View file

@ -0,0 +1,2 @@
---
# sample kubernetes config

View file

@ -0,0 +1,4 @@
---
# url: https://proxmox.host.or.ip:8006
# token: username@pam!Token ID
# secret: secret

View file

@ -0,0 +1,18 @@
---
# For configuration options and examples, please see:
# https://gethomepage.dev/configs/services/
- My First Group:
- My First Service:
href: http://localhost/
description: Homepage is awesome
- My Second Group:
- My Second Service:
href: http://localhost/
description: Homepage is the best
- My Third Group:
- My Third Service:
href: http://localhost/
description: Homepage is 😎

View file

@ -0,0 +1,7 @@
---
# For configuration options and examples, please see:
# https://gethomepage.dev/configs/settings/
providers:
openweathermap: openweathermapapikey
weatherapi: weatherapiapikey

View file

@ -0,0 +1,12 @@
---
# For configuration options and examples, please see:
# https://gethomepage.dev/configs/info-widgets/
- resources:
cpu: true
memory: true
disk: /
- search:
provider: duckduckgo
target: _blank

View file

@ -0,0 +1,34 @@
---
- name: Ensure data directories exist
ansible.builtin.file:
path: "{{ container_homepage_directory }}/data/{{ item }}"
state: directory
mode: '0755'
loop:
- "config"
become: false
- name: Deploy Docker Compose and .env files
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ container_homepage_directory }}/{{ item.dest }}"
mode: '0644'
loop:
- { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' }
- { src: '.env.j2', dest: '.env' }
become: false
- name: Deploy tenant-specific config files
ansible.builtin.copy:
src: "{{ item.src }}"
dest: "{{ container_homepage_directory }}/data/config/{{ item.dest }}"
mode: '0644'
loop: "{{ container_homepage_config_files }}"
become: false
- name: Start Container
community.docker.docker_compose_v2:
project_src: "{{ container_homepage_directory }}"
pull: always
docker_host: "unix:///run/user/1000/docker.sock"
become: false

View file

@ -0,0 +1,2 @@
HOMEPAGE_VERSION={{ container_homepage_version }}
HOMEPAGE_DOMAIN={{ container_homepage_domain }}

View file

@ -0,0 +1,29 @@
---
services:
homepage:
image: ghcr.io/gethomepage/homepage:${HOMEPAGE_VERSION}
container_name: homepage
restart: always
networks:
- traefik
volumes:
- ./data/config:/app/config
- /run/user/1000/docker.sock:/var/run/docker.sock:ro
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.homepage.entrypoints=http"
- "traefik.http.routers.homepage.rule=Host(`${HOMEPAGE_DOMAIN}`)"
- "traefik.http.middlewares.homepage-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.homepage.middlewares=homepage-https-redirect"
- "traefik.http.routers.homepage-secure.entrypoints=https"
- "traefik.http.routers.homepage-secure.rule=Host(`${HOMEPAGE_DOMAIN}`)"
- "traefik.http.routers.homepage-secure.tls=true"
- "traefik.http.routers.homepage-secure.service=homepage"
- "traefik.http.services.homepage.loadbalancer.server.port=3000"
environment:
HOMEPAGE_ALLOWED_HOSTS: "*"
networks:
traefik:
external: true

View file

@ -0,0 +1,35 @@
---
container_traefik_version: "latest"
container_traefik_http_port: 80
container_traefik_https_port: 443
container_traefik_domain: "example.com"
container_traefik_san_domains:
- "example.com"
- "example.org"
container_traefik_cloudflare_mail: "your-email@example.com"
container_traefik_cloudflare_token: "your-cloudflare-token"
container_traefik_basicauth_user: "admin"
container_traefik_basicauth_password: "yourpassword"
# Static Traefik Routes
container_traefik_routers:
traefik:
entryPoints:
- "https"
rule: "Host(`example.example.com`)"
middlewares:
- default-headers
tls: {}
service: traefik
container_traefik_services:
traefik:
loadBalancer:
servers:
- url: "http://127.0.0.1"
passHostHeader: true
serversTransport: insecure-https
container_traefik_serversTransports:
insecure-https:
insecureSkipVerify: true

View file

@ -0,0 +1,57 @@
---
- name: Ensure data directories exist
ansible.builtin.file:
path: "{{ traefik_container_dir }}/data/{{ item }}"
state: directory
mode: '0755'
loop:
- "traefik"
- "certs"
- "logs"
- "traefik/config.d"
become: false
- name: Ensure log files exist
ansible.builtin.file:
path: "{{ traefik_container_dir }}/data/logs/{{ item }}"
state: touch
mode: '0644'
loop:
- "traefik.log"
- "access.log"
become: false
- name: Deploy Traefik configuration files
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ traefik_container_dir }}/data/{{ item.dest }}"
mode: '0644'
loop:
- { src: 'traefik.yml.j2', dest: 'traefik/traefik.yml' }
- { src: 'default.yml.j2', dest: 'traefik/config.d/default.yml' }
- { src: 'hosts.yml.j2', dest: 'traefik/config.d/hosts.yml' }
become: false
- name: Deploy Docker Compose and .env files
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ traefik_container_dir }}/{{ item.dest }}"
mode: '0644'
loop:
- { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' }
- { src: '.env.j2', dest: '.env' }
become: false
- name: Ensure Docker network exists
community.docker.docker_network:
name: traefik
state: present
docker_host: "unix:///run/user/1000/docker.sock"
become: false
- name: Start Traefik container
community.docker.docker_compose_v2:
project_src: "{{ traefik_container_dir }}"
pull: always
docker_host: "unix:///run/user/1000/docker.sock"
become: false

View file

@ -0,0 +1,29 @@
# Traefik Version
# Defines the version of Traefik to be used. By default, "latest" is used.
TRAEFIK_VERSION={{ container_traefik_version }}
TRAEFIK_DOMAIN={{ container_traefik_domain }}
# Ports
# Defines the ports on which Traefik will be available for HTTP and HTTPS traffic.
# By default, these are 80 (HTTP) and 443 (HTTPS).
TRAEFIK_HTTP_PORT={{ container_traefik_http_port }}
TRAEFIK_HTTPS_PORT={{ container_traefik_https_port }}
# Cloudflare API Access
# Your Cloudflare API credentials that Traefik uses to automatically obtain TLS certificates
# via the Cloudflare DNS provider.
# Replace the following placeholders with your actual Cloudflare details:
# - CLOUDFLARE_MAIL: Your Cloudflare email address
# - CLOUDFLARE_TOKEN: Your Cloudflare API token
CLOUDFLARE_MAIL={{ container_traefik_cloudflare_mail }}
CLOUDFLARE_TOKEN={{ container_traefik_cloudflare_token }}
# Basic Auth Configuration
# Basic authentication credentials for securing the Traefik dashboard.
# You can generate the password using the following command:
# echo $(htpasswd -nB yourusername) | sed -e s/\\$/\\$\\$/g
# Replace `yourusername` with the desired username.
# The generated value can then be placed in the `BASICAUTH_PASSWORD` variable.
TRAEFIK_BASICAUTH_USER={{ container_traefik_basicauth_user }}
TRAEFIK_BASICAUTH_PASSWORD={{ container_traefik_basicauth_password }}

View file

@ -0,0 +1,19 @@
http:
middlewares:
https-redirect:
redirectScheme:
scheme: https
default-headers:
headers:
frameDeny: true
sslRedirect: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 15552000
customFrameOptionsValue: SAMEORIGIN
customRequestHeaders:
X-Forwarded-Proto: https

View file

@ -0,0 +1,44 @@
---
services:
traefik:
image: traefik:${TRAEFIK_VERSION}
container_name: traefik
restart: always
security_opt:
- "no-new-privileges:true"
networks:
- traefik
ports:
- ${TRAEFIK_HTTP_PORT}:80
- ${TRAEFIK_HTTPS_PORT}:443
volumes:
- /run/user/1000/docker.sock:/var/run/docker.sock:ro
- ./data/traefik:/etc/traefik
- ./data/certs:/etc/certs:ro
- ./data/logs/traefik.log:/var/log/traefik.log
- ./data/logs/access.log:/var/log/crowdsec/traefik.log
environment:
- "CF_API_EMAIL=${CLOUDFLARE_MAIL:?error}"
- "CF_DNS_API_TOKEN=${CLOUDFLARE_TOKEN:?error}"
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN}`)"
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
- "traefik.http.routers.traefik-secure.entrypoints=https"
- "traefik.http.middlewares.basic-auth.basicauth.users=${TRAEFIK_BASICAUTH_USER}:${TRAEFIK_BASICAUTH_PASSWORD}"
- "traefik.http.routers.traefik-secure.middlewares=basic-auth"
- "traefik.http.routers.traefik-secure.rule=Host(`${TRAEFIK_DOMAIN}`)"
- "traefik.http.routers.traefik-secure.tls=true"
- "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
{% for domain in container_traefik_san_domains %}
- "traefik.http.routers.traefik-secure.tls.domains[{{ loop.index0 }}].main={{ domain }}"
- "traefik.http.routers.traefik-secure.tls.domains[{{ loop.index0 }}].sans=*.{{ domain }}"
{% endfor %}
- "traefik.http.routers.traefik-secure.service=api@internal"
networks:
traefik:
external: true

View file

@ -0,0 +1,42 @@
http:
routers:
{% for router_name, router in container_traefik_routers.items() %}
{{ router_name }}:
entryPoints:
{% for ep in router.entryPoints %}
- "{{ ep }}"
{% endfor %}
rule: "{{ router.rule }}"
{% if router.middlewares is defined and router.middlewares %}
middlewares:
{% for m in router.middlewares %}
- {{ m }}
{% endfor %}
{% endif %}
{% if router.tls is defined and router.tls %}
tls: {}
{% endif %}
service: {{ router.service }}
{% endfor %}
services:
{% for service_name, service in container_traefik_services.items() %}
{{ service_name }}:
loadBalancer:
servers:
{% for server in service.loadBalancer.servers %}
- url: "{{ server.url }}"
{% endfor %}
passHostHeader: {{ service.loadBalancer.passHostHeader | default(true) | lower }}
{% if service.loadBalancer.serversTransport is defined %}
serversTransport: {{ service.loadBalancer.serversTransport }}
{% endif %}
{% endfor %}
serversTransports:
{% for transport_name, transport in container_traefik_serversTransports.items() %}
{{ transport_name }}:
{% for key, value in transport.items() %}
{{ key }}: {{ value | lower if value is boolean else value }}
{% endfor %}
{% endfor %}

View file

@ -0,0 +1,43 @@
api:
dashboard: true
log:
level: INFO
format: json
filePath: "/var/log/traefik.log"
accessLog:
filePath: "/var/log/access.log"
bufferingSize: 50
entryPoints:
http:
address: ":80"
https:
address: ":443"
serversTransport:
insecureSkipVerify: false
forwardingTimeouts:
dialTimeout: 10s
responseHeaderTimeout: 10s
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
watch: true
file:
directory: "/etc/traefik/config.d/"
watch: true
certificatesResolvers:
cloudflare:
acme:
email: "{{ container_traefik_cloudflare_mail }}"
storage: acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"

View file

@ -0,0 +1,2 @@
---
traefik_container_dir: "/opt/docker/traefik"

View file

@ -0,0 +1,5 @@
---
fail2ban_ssh_enabled: true
fail2ban_ssh_maxretry: 5
fail2ban_ssh_bantime: 1h
fail2ban_ssh_findtime: 1h

View file

@ -0,0 +1,5 @@
---
- name: Restart fail2ban
ansible.builtin.service:
name: fail2ban
state: restarted

View file

@ -0,0 +1,23 @@
---
- name: Update apt package index
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Install Fail2Ban
ansible.builtin.apt:
name: fail2ban
state: present
- name: Ensure Fail2Ban service is enabled and running
ansible.builtin.service:
name: fail2ban
enabled: true
state: started
- name: Configure Fail2Ban for SSH
ansible.builtin.template:
src: jail.local.j2
dest: /etc/fail2ban/jail.local
mode: '0644'
notify: Restart fail2ban

View file

@ -0,0 +1,15 @@
[DEFAULT]
# Ignore local IP addresses
ignoreip = 127.0.0.1/8 ::1
# Ban settings
bantime = {{ fail2ban_ssh_bantime }}
findtime = {{ fail2ban_ssh_findtime }}
maxretry = {{ fail2ban_ssh_maxretry }}
[sshd]
enabled = {{ fail2ban_ssh_enabled | lower }}
port = ssh
filter = sshd
logpath = %(sshd_log)s
maxretry = {{ fail2ban_ssh_maxretry }}

View file

@ -0,0 +1,8 @@
# Standard-SSH-Benutzer
ssh_user: skulladmin
# Platzhalter-Key
ssh_public_key: ""
# SSH-Port
ssh_port: 22

View file

@ -0,0 +1,5 @@
---
- name: Restart SSH
ansible.builtin.service:
name: ssh
state: restarted

View file

View file

@ -0,0 +1,41 @@
---
- name: Paketlisten aktualisieren
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: OpenSSH Server installieren
ansible.builtin.apt:
name: openssh-server
state: present
- name: Benutzer anlegen (falls nicht vorhanden)
ansible.builtin.user:
name: "{{ ssh_user }}"
shell: /bin/bash
create_home: true
- name: SSH-Verzeichnis anlegen
ansible.builtin.file:
path: "/home/{{ ssh_user }}/.ssh"
state: directory
owner: "{{ ssh_user }}"
group: "{{ ssh_user }}"
mode: '0700'
- name: SSH-Key eintragen
ansible.builtin.copy:
content: "{{ ssh_public_key }}"
dest: "/home/{{ ssh_user }}/.ssh/authorized_keys"
owner: "{{ ssh_user }}"
group: "{{ ssh_user }}"
mode: '0600'
- name: SSH-Konfiguration per Template übertragen
ansible.builtin.template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: '0644'
notify: Restart SSH

View file

@ -0,0 +1,17 @@
# OpenSSH server configuration (managed by Ansible)
Port {{ ssh_port }}
Protocol 2
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 30
MaxAuthTries 3
AllowTcpForwarding no
PermitEmptyPasswords no
PrintMotd no
UseDNS no
Compression no

View file

View file

@ -0,0 +1,6 @@
---
- name: Start and enable rsyslog
ansible.builtin.service:
name: rsyslog
state: started
enabled: true

View file

@ -0,0 +1,17 @@
---
- name: Update apt package index
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Install rsyslog
ansible.builtin.apt:
name: rsyslog
state: present
notify: Start and enable rsyslog
- name: Enable rsyslog
ansible.builtin.service:
name: rsyslog
state: started
enabled: true

View file

View file

View file

View file

View file

View file

View file