updates
This commit is contained in:
parent
c959b4581c
commit
d5e3ce88a3
52 changed files with 2560 additions and 65 deletions
10
CLAUDE.md
10
CLAUDE.md
|
|
@ -31,14 +31,16 @@ make facts
|
||||||
```
|
```
|
||||||
|
|
||||||
### Terraform Operations
|
### Terraform Operations
|
||||||
|
**IMPORTANT**: Use OpenTofu (tofu) instead of terraform for all operations.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd terraform
|
cd terraform
|
||||||
terraform init
|
tofu init
|
||||||
terraform plan
|
tofu plan
|
||||||
terraform apply
|
tofu apply
|
||||||
|
|
||||||
# Format terraform files before committing
|
# Format terraform files before committing
|
||||||
terraform fmt
|
tofu fmt
|
||||||
```
|
```
|
||||||
|
|
||||||
### K3s Cluster Deployment (VNTX)
|
### K3s Cluster Deployment (VNTX)
|
||||||
|
|
|
||||||
53
ansible/MAILCOW_SETUP.md
Normal file
53
ansible/MAILCOW_SETUP.md
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Mailcow Setup Instructions
|
||||||
|
|
||||||
|
## Current Status
|
||||||
|
|
||||||
|
1. **DNS Records Applied** ✅
|
||||||
|
- A records: mail.w5isp.com, mail.mcintire.me → 204.110.191.216
|
||||||
|
- Autodiscover/Autoconfig records for both domains
|
||||||
|
- MX record for w5isp.com → mail.w5isp.com
|
||||||
|
- SPF record for w5isp.com: `v=spf1 mx a ip4:204.110.191.216 ~all`
|
||||||
|
- DMARC record for w5isp.com with quarantine policy
|
||||||
|
- DKIM placeholder (needs actual key from Mailcow)
|
||||||
|
|
||||||
|
2. **Mailcow Deployed** ✅
|
||||||
|
- Running on sync.w5isp.com with Docker Compose
|
||||||
|
- All containers running successfully
|
||||||
|
- Web interface accessible via HTTPS (Mailcow includes nginx)
|
||||||
|
- No additional reverse proxy needed - Mailcow's nginx handles SSL
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
### 1. Access Mailcow Web UI
|
||||||
|
Access the web interface at: https://mail.w5isp.com
|
||||||
|
Default admin login: admin / moohoo (change immediately!)
|
||||||
|
|
||||||
|
### 3. Configure Domains in Mailcow
|
||||||
|
1. Log into Mailcow admin panel
|
||||||
|
2. Go to Configuration → Domains
|
||||||
|
3. Add domain: w5isp.com
|
||||||
|
4. Add domain: mcintire.me (for receiving only, MX still points to ProtonMail)
|
||||||
|
|
||||||
|
### 4. Get DKIM Key and Update DNS
|
||||||
|
1. In Mailcow: Configuration → Domains → w5isp.com → DKIM
|
||||||
|
2. Copy the public key
|
||||||
|
3. Update the DKIM record in `terraform/dns_w5isp.tf`
|
||||||
|
4. Apply with `tofu apply`
|
||||||
|
|
||||||
|
### 5. Create Mailboxes
|
||||||
|
1. Go to Mailboxes → Add mailbox
|
||||||
|
2. Create postmaster@w5isp.com (required for DMARC reports)
|
||||||
|
3. Create any other mailboxes needed
|
||||||
|
|
||||||
|
### 6. Test Mail Delivery
|
||||||
|
1. Send test email to/from w5isp.com addresses
|
||||||
|
2. Check mail logs in Mailcow UI
|
||||||
|
3. Verify DMARC/SPF/DKIM with mail-tester.com
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
- mcintire.me remains with ProtonMail (MX records unchanged)
|
||||||
|
- Only w5isp.com is fully migrated to Mailcow
|
||||||
|
- Firewall ports 25, 587, 465, 143, 993, 110, 995 are opened by the role
|
||||||
|
- Mailcow data is stored in /opt/mailcow-dockerized
|
||||||
|
- The mail server IP is 204.110.191.216 (sync.w5isp.com)
|
||||||
3
ansible/host_vars/apps.w5isp.com.yml
Normal file
3
ansible/host_vars/apps.w5isp.com.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
# Host-specific variables for apps.w5isp.com
|
||||||
|
ansible_remote_tmp: /tmp/.ansible-${USER}/tmp
|
||||||
3
ansible/host_vars/caddy.w5isp.com.yml
Normal file
3
ansible/host_vars/caddy.w5isp.com.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
# Host-specific variables for caddy.w5isp.com
|
||||||
|
ansible_python_interpreter: /usr/bin/python3.12
|
||||||
7
ansible/host_vars/sync.w5isp.com.vault.yml
Normal file
7
ansible/host_vars/sync.w5isp.com.vault.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
# Vault file for sync.w5isp.com - Mailcow secrets
|
||||||
|
|
||||||
|
vault_mailcow_api_key: "drVv1AtEHuJw5C0+MxlKGGOMYiLx7C6dlfcAFlh2wZY="
|
||||||
|
vault_mailcow_dbpass: "om30XAgUbHTcPy3uGNzJAp8L+uGvNyoS"
|
||||||
|
vault_mailcow_dbroot: "jhIXyrY/DOS8wuRPSmCuRR/DqqXzi2Lq"
|
||||||
|
vault_mailcow_redispass: "9YZCv2mqofPYl7p4ep5DvL2PVBIBhMK/"
|
||||||
15
ansible/host_vars/sync.w5isp.com.yml
Normal file
15
ansible/host_vars/sync.w5isp.com.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
# Host-specific variables for sync.w5isp.com
|
||||||
|
ansible_user: ansible
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
|
||||||
|
# Mailcow configuration
|
||||||
|
mailcow_hostname: mail.w5isp.com
|
||||||
|
mailcow_http_bind: "127.0.0.1"
|
||||||
|
mailcow_https_bind: "127.0.0.1"
|
||||||
|
mailcow_api_key: "{{ vault_mailcow_api_key }}"
|
||||||
|
mailcow_dbpass: "{{ vault_mailcow_dbpass }}"
|
||||||
|
mailcow_dbroot: "{{ vault_mailcow_dbroot }}"
|
||||||
|
|
||||||
|
# Since we're using Caddy as reverse proxy
|
||||||
|
mailcow_skip_lets_encrypt: "y"
|
||||||
25
ansible/host_vars/w5isp.w5isp.com.yml
Normal file
25
ansible/host_vars/w5isp.w5isp.com.yml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
# Host-specific variables for w5isp.w5isp.com
|
||||||
|
ansible_user: ansible
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
|
||||||
|
# K3s configuration for single-node setup
|
||||||
|
k3s_version: v1.28.5+k3s1
|
||||||
|
k3s_install_exec: >-
|
||||||
|
--disable servicelb
|
||||||
|
--write-kubeconfig-mode 644
|
||||||
|
--cluster-cidr=10.42.0.0/16
|
||||||
|
--service-cidr=10.43.0.0/16
|
||||||
|
--cluster-dns=10.43.0.10
|
||||||
|
--flannel-backend=vxlan
|
||||||
|
|
||||||
|
# Network configuration
|
||||||
|
k3s_server_ip: 204.110.191.200
|
||||||
|
|
||||||
|
# DNS configuration
|
||||||
|
nameservers:
|
||||||
|
- 9.9.9.9
|
||||||
|
- 149.112.112.112
|
||||||
|
|
||||||
|
# Tailscale configuration (if needed)
|
||||||
|
tailscale_enabled: false
|
||||||
|
|
@ -11,13 +11,13 @@ ns2.vntx.net
|
||||||
#ntp.vntx.net
|
#ntp.vntx.net
|
||||||
|
|
||||||
[app_servers]
|
[app_servers]
|
||||||
#aprs.me
|
|
||||||
dallas.aprs2.net
|
dallas.aprs2.net
|
||||||
apps.w5isp.com
|
apps.w5isp.com
|
||||||
|
|
||||||
[home_servers]
|
[home_servers]
|
||||||
skippy.w5isp.com
|
skippy.w5isp.com
|
||||||
g.w5isp.com
|
sync.w5isp.com ansible_host=204.110.191.216
|
||||||
|
w5isp.w5isp.com ansible_host=204.110.191.200
|
||||||
|
|
||||||
[proxmox]
|
[proxmox]
|
||||||
lab02.w5isp.com
|
lab02.w5isp.com
|
||||||
|
|
@ -29,9 +29,24 @@ lab02.w5isp.com
|
||||||
lab03.w5isp.com
|
lab03.w5isp.com
|
||||||
lab04.w5isp.com
|
lab04.w5isp.com
|
||||||
g.w5isp.com
|
g.w5isp.com
|
||||||
|
sync.w5isp.com
|
||||||
|
|
||||||
[caddy_servers]
|
[caddy_servers]
|
||||||
g.w5isp.com
|
caddy.w5isp.com
|
||||||
|
|
||||||
|
[k3s_servers]
|
||||||
|
home-k3s-control-1 ansible_host=10.0.19.100
|
||||||
|
home-k3s-control-2 ansible_host=10.0.19.101
|
||||||
|
home-k3s-control-3 ansible_host=10.0.19.102
|
||||||
|
home-k3s-worker-1 ansible_host=10.0.19.110
|
||||||
|
home-k3s-worker-2 ansible_host=10.0.19.111
|
||||||
|
home-k3s-worker-3 ansible_host=10.0.19.112
|
||||||
|
|
||||||
|
[syncthing_servers]
|
||||||
|
sync.w5isp.com
|
||||||
|
|
||||||
[postgresql_servers]
|
[postgresql_servers]
|
||||||
postgres ansible_host=10.0.19.224
|
#postgres ansible_host=10.0.19.224
|
||||||
|
|
||||||
|
[mailcow_servers]
|
||||||
|
sync.w5isp.com
|
||||||
|
|
|
||||||
10
ansible/mailcow.yml
Normal file
10
ansible/mailcow.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
# Deploy Mailcow mail server
|
||||||
|
|
||||||
|
- name: Deploy Mailcow
|
||||||
|
hosts: mailcow_servers
|
||||||
|
become: yes
|
||||||
|
vars_files:
|
||||||
|
- host_vars/sync.w5isp.com.vault.yml
|
||||||
|
roles:
|
||||||
|
- mailcow
|
||||||
|
|
@ -139,6 +139,59 @@
|
||||||
- raid
|
- raid
|
||||||
- postgresql
|
- postgresql
|
||||||
|
|
||||||
|
# Plays from general.yml
|
||||||
|
- name: Apply general configuration to all nodes
|
||||||
|
hosts: all
|
||||||
|
become: yes
|
||||||
|
become_method: sudo
|
||||||
|
roles:
|
||||||
|
- general
|
||||||
|
tags:
|
||||||
|
- general
|
||||||
|
|
||||||
|
- name: SNMP clients
|
||||||
|
hosts: snmp_clients
|
||||||
|
become: yes
|
||||||
|
become_method: sudo
|
||||||
|
roles:
|
||||||
|
- snmp_clients
|
||||||
|
tags:
|
||||||
|
- snmp
|
||||||
|
|
||||||
|
- name: k3s
|
||||||
|
hosts: k3s_servers
|
||||||
|
become: yes
|
||||||
|
become_method: sudo
|
||||||
|
tags: k3s
|
||||||
|
roles:
|
||||||
|
- k3s_servers
|
||||||
|
|
||||||
|
- name: Docker servers
|
||||||
|
hosts: docker
|
||||||
|
become: yes
|
||||||
|
become_method: sudo
|
||||||
|
tags: docker
|
||||||
|
roles:
|
||||||
|
- docker
|
||||||
|
vars:
|
||||||
|
gpg_fingerprint: "9DC858229FC7DD38854AE2D88D81803C0EBFCD88"
|
||||||
|
|
||||||
|
- name: Syslog servers
|
||||||
|
hosts: syslog
|
||||||
|
become: yes
|
||||||
|
become_method: sudo
|
||||||
|
tags: syslog
|
||||||
|
roles:
|
||||||
|
- syslog_servers
|
||||||
|
|
||||||
|
- name: Syncthing servers
|
||||||
|
hosts: syncthing_servers
|
||||||
|
become: yes
|
||||||
|
become_method: sudo
|
||||||
|
tags: syncthing
|
||||||
|
roles:
|
||||||
|
- syncthing
|
||||||
|
|
||||||
# - import_playbook: baseline/proxmox/main.yml
|
# - import_playbook: baseline/proxmox/main.yml
|
||||||
# - name: Tailscale Home
|
# - name: Tailscale Home
|
||||||
# hosts: tailscale_home
|
# hosts: tailscale_home
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
- name: Clean DNF cache
|
- name: Clean DNF cache
|
||||||
ansible.builtin.command: dnf clean all
|
ansible.builtin.command: dnf clean all
|
||||||
args:
|
|
||||||
warn: false
|
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: Upgrade all packages
|
- name: Upgrade all packages
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,15 @@
|
||||||
when: ansible_os_family == "Debian"
|
when: ansible_os_family == "Debian"
|
||||||
|
|
||||||
- name: Add Caddy GPG key (Debian/Ubuntu)
|
- name: Add Caddy GPG key (Debian/Ubuntu)
|
||||||
apt_key:
|
get_url:
|
||||||
url: "https://dl.cloudsmith.io/public/caddy/stable/gpg.key"
|
url: "https://dl.cloudsmith.io/public/caddy/stable/gpg.key"
|
||||||
state: present
|
dest: /etc/apt/trusted.gpg.d/caddy-stable.asc
|
||||||
|
mode: '0644'
|
||||||
when: ansible_os_family == "Debian"
|
when: ansible_os_family == "Debian"
|
||||||
|
|
||||||
- name: Add Caddy repository (Debian/Ubuntu)
|
- name: Add Caddy repository (Debian/Ubuntu)
|
||||||
apt_repository:
|
apt_repository:
|
||||||
repo: "deb https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main"
|
repo: "deb [signed-by=/etc/apt/trusted.gpg.d/caddy-stable.asc] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main"
|
||||||
state: present
|
state: present
|
||||||
filename: caddy-stable
|
filename: caddy-stable
|
||||||
when: ansible_os_family == "Debian"
|
when: ansible_os_family == "Debian"
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,38 @@ truck.w5isp.com {
|
||||||
photos.w5isp.com {
|
photos.w5isp.com {
|
||||||
reverse_proxy http://10.0.16.1:2283
|
reverse_proxy http://10.0.16.1:2283
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Mailcow configuration
|
||||||
|
mail.w5isp.com {
|
||||||
|
reverse_proxy http://204.110.191.216:8080 {
|
||||||
|
header_up Host {host}
|
||||||
|
header_up X-Real-IP {remote}
|
||||||
|
header_up X-Forwarded-For {remote}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
autodiscover.w5isp.com {
|
||||||
|
reverse_proxy http://204.110.191.216:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
autoconfig.w5isp.com {
|
||||||
|
reverse_proxy http://204.110.191.216:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
mail.mcintire.me {
|
||||||
|
reverse_proxy http://204.110.191.216:8080 {
|
||||||
|
header_up Host {host}
|
||||||
|
header_up X-Real-IP {remote}
|
||||||
|
header_up X-Forwarded-For {remote}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
autodiscover.mcintire.me {
|
||||||
|
reverse_proxy http://204.110.191.216:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
autoconfig.mcintire.me {
|
||||||
|
reverse_proxy http://204.110.191.216:8080
|
||||||
|
}
|
||||||
|
|
|
||||||
48
ansible/roles/mailcow/defaults/main.yml
Normal file
48
ansible/roles/mailcow/defaults/main.yml
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
---
|
||||||
|
# Default variables for Mailcow
|
||||||
|
|
||||||
|
mailcow_hostname: "{{ inventory_hostname }}"
|
||||||
|
mailcow_timezone: "America/Chicago"
|
||||||
|
mailcow_base_path: /opt/mailcow-dockerized
|
||||||
|
|
||||||
|
# API configuration
|
||||||
|
mailcow_api_key: "{{ vault_mailcow_api_key | default('') }}"
|
||||||
|
mailcow_api_allow_ips: "127.0.0.1,::1"
|
||||||
|
|
||||||
|
# HTTP/HTTPS bindings
|
||||||
|
mailcow_http_bind: "127.0.0.1"
|
||||||
|
mailcow_http_port: 8080
|
||||||
|
mailcow_https_bind: "127.0.0.1"
|
||||||
|
mailcow_https_port: 8443
|
||||||
|
|
||||||
|
# Mail ports - bind to all interfaces
|
||||||
|
mailcow_smtp_port: 25
|
||||||
|
mailcow_submission_port: 587
|
||||||
|
mailcow_smtps_port: 465
|
||||||
|
mailcow_imap_port: 143
|
||||||
|
mailcow_imaps_port: 993
|
||||||
|
mailcow_pop3_port: 110
|
||||||
|
mailcow_pop3s_port: 995
|
||||||
|
|
||||||
|
# Database configuration
|
||||||
|
mailcow_dbname: mailcow
|
||||||
|
mailcow_dbuser: mailcow
|
||||||
|
mailcow_dbpass: "{{ vault_mailcow_dbpass | default('') }}"
|
||||||
|
mailcow_dbroot: "{{ vault_mailcow_dbroot | default('') }}"
|
||||||
|
|
||||||
|
# Skip various checks
|
||||||
|
mailcow_skip_lets_encrypt: "y"
|
||||||
|
mailcow_skip_sogo: "n"
|
||||||
|
mailcow_skip_clamd: "n"
|
||||||
|
mailcow_skip_solr: "n"
|
||||||
|
mailcow_additional_san: ""
|
||||||
|
|
||||||
|
# Compose project name
|
||||||
|
mailcow_compose_project_name: mailcowdockerized
|
||||||
|
|
||||||
|
# Git repository
|
||||||
|
mailcow_git_repo: https://github.com/mailcow/mailcow-dockerized.git
|
||||||
|
mailcow_git_branch: master
|
||||||
|
|
||||||
|
# External mail storage path (outside Docker)
|
||||||
|
mailcow_vmail_path: /opt/mailcow-mail
|
||||||
15
ansible/roles/mailcow/handlers/main.yml
Normal file
15
ansible/roles/mailcow/handlers/main.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
# Handlers for Mailcow
|
||||||
|
|
||||||
|
- name: restart mailcow
|
||||||
|
systemd:
|
||||||
|
name: mailcow
|
||||||
|
state: restarted
|
||||||
|
daemon_reload: yes
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: reload mailcow
|
||||||
|
command: docker compose restart
|
||||||
|
args:
|
||||||
|
chdir: "{{ mailcow_base_path }}"
|
||||||
|
|
||||||
196
ansible/roles/mailcow/tasks/main.yml
Normal file
196
ansible/roles/mailcow/tasks/main.yml
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
---
|
||||||
|
# Install and configure Mailcow
|
||||||
|
|
||||||
|
- name: Install required packages
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- git
|
||||||
|
- curl
|
||||||
|
- docker.io
|
||||||
|
- docker-compose
|
||||||
|
- python3-pip
|
||||||
|
- python3-docker
|
||||||
|
- jq
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Ensure docker service is running
|
||||||
|
systemd:
|
||||||
|
name: docker
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
|
||||||
|
- name: Create mailcow user
|
||||||
|
user:
|
||||||
|
name: mailcow
|
||||||
|
groups: docker
|
||||||
|
shell: /bin/bash
|
||||||
|
home: /home/mailcow
|
||||||
|
create_home: yes
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensure mailcow base directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ mailcow_base_path }}"
|
||||||
|
state: directory
|
||||||
|
owner: mailcow
|
||||||
|
group: mailcow
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Check if Mailcow repository exists
|
||||||
|
stat:
|
||||||
|
path: "{{ mailcow_base_path }}/.git"
|
||||||
|
register: mailcow_repo
|
||||||
|
|
||||||
|
- name: Remove non-git Mailcow directory
|
||||||
|
file:
|
||||||
|
path: "{{ mailcow_base_path }}"
|
||||||
|
state: absent
|
||||||
|
when:
|
||||||
|
- mailcow_base_path is defined
|
||||||
|
- not mailcow_repo.stat.exists
|
||||||
|
|
||||||
|
- name: Clone Mailcow repository
|
||||||
|
git:
|
||||||
|
repo: "{{ mailcow_git_repo }}"
|
||||||
|
dest: "{{ mailcow_base_path }}"
|
||||||
|
version: "{{ mailcow_git_branch }}"
|
||||||
|
force: yes
|
||||||
|
when: not mailcow_repo.stat.exists
|
||||||
|
|
||||||
|
- name: Add Mailcow directory to git safe directories
|
||||||
|
command: git config --global --add safe.directory {{ mailcow_base_path }}
|
||||||
|
when: mailcow_repo.stat.exists
|
||||||
|
|
||||||
|
- name: Update Mailcow repository
|
||||||
|
git:
|
||||||
|
repo: "{{ mailcow_git_repo }}"
|
||||||
|
dest: "{{ mailcow_base_path }}"
|
||||||
|
version: "{{ mailcow_git_branch }}"
|
||||||
|
update: yes
|
||||||
|
when: mailcow_repo.stat.exists
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Change ownership of Mailcow directory
|
||||||
|
file:
|
||||||
|
path: "{{ mailcow_base_path }}"
|
||||||
|
owner: mailcow
|
||||||
|
group: mailcow
|
||||||
|
recurse: yes
|
||||||
|
|
||||||
|
# Let generate_config.sh create the default configuration
|
||||||
|
|
||||||
|
- name: Create docker-compose override file
|
||||||
|
template:
|
||||||
|
src: docker-compose.override.yml.j2
|
||||||
|
dest: "{{ mailcow_base_path }}/docker-compose.override.yml"
|
||||||
|
owner: mailcow
|
||||||
|
group: mailcow
|
||||||
|
mode: '0640'
|
||||||
|
backup: yes
|
||||||
|
notify: restart mailcow
|
||||||
|
|
||||||
|
- name: Make generate_config.sh executable
|
||||||
|
file:
|
||||||
|
path: "{{ mailcow_base_path }}/generate_config.sh"
|
||||||
|
mode: '0755'
|
||||||
|
owner: mailcow
|
||||||
|
group: mailcow
|
||||||
|
|
||||||
|
- name: Check if mailcow is already configured
|
||||||
|
stat:
|
||||||
|
path: "{{ mailcow_base_path }}/mailcow.conf"
|
||||||
|
register: mailcow_configured
|
||||||
|
|
||||||
|
- name: Remove incomplete mailcow.conf
|
||||||
|
file:
|
||||||
|
path: "{{ mailcow_base_path }}/mailcow.conf"
|
||||||
|
state: absent
|
||||||
|
when:
|
||||||
|
- mailcow_configured.stat.exists
|
||||||
|
- mailcow_configured.stat.size < 1000 # If config is too small, it's incomplete
|
||||||
|
|
||||||
|
- name: Run generate_config.sh script
|
||||||
|
shell: |
|
||||||
|
cd {{ mailcow_base_path }}
|
||||||
|
./generate_config.sh << EOF
|
||||||
|
{{ mailcow_hostname }}
|
||||||
|
{{ mailcow_timezone }}
|
||||||
|
EOF
|
||||||
|
args:
|
||||||
|
creates: "{{ mailcow_base_path }}/mailcow.conf"
|
||||||
|
|
||||||
|
- name: Update mailcow.conf with secure passwords
|
||||||
|
lineinfile:
|
||||||
|
path: "{{ mailcow_base_path }}/mailcow.conf"
|
||||||
|
regexp: "^{{ item.key }}="
|
||||||
|
line: "{{ item.key }}={{ item.value }}"
|
||||||
|
state: present
|
||||||
|
loop:
|
||||||
|
- { key: "DBPASS", value: "{{ vault_mailcow_dbpass }}" }
|
||||||
|
- { key: "DBROOT", value: "{{ vault_mailcow_dbroot }}" }
|
||||||
|
- { key: "REDISPASS", value: "{{ vault_mailcow_redispass }}" }
|
||||||
|
- { key: "API_KEY", value: "{{ vault_mailcow_api_key }}" }
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Stop any running Mailcow containers
|
||||||
|
command: docker compose down
|
||||||
|
args:
|
||||||
|
chdir: "{{ mailcow_base_path }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Prune unused Docker networks
|
||||||
|
command: docker network prune -f
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Pull docker images
|
||||||
|
command: docker compose pull
|
||||||
|
args:
|
||||||
|
chdir: "{{ mailcow_base_path }}"
|
||||||
|
|
||||||
|
- name: Start Mailcow services
|
||||||
|
command: docker compose up -d
|
||||||
|
args:
|
||||||
|
chdir: "{{ mailcow_base_path }}"
|
||||||
|
|
||||||
|
- name: Check if ufw is installed
|
||||||
|
command: which ufw
|
||||||
|
register: ufw_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Configure firewall for mail services
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ item.port }}"
|
||||||
|
proto: "{{ item.proto }}"
|
||||||
|
comment: "{{ item.comment }}"
|
||||||
|
loop:
|
||||||
|
- { port: "25", proto: "tcp", comment: "SMTP" }
|
||||||
|
- { port: "587", proto: "tcp", comment: "SMTP Submission" }
|
||||||
|
- { port: "465", proto: "tcp", comment: "SMTPS" }
|
||||||
|
# - { port: "143", proto: "tcp", comment: "IMAP" } # Disabled non-TLS
|
||||||
|
- { port: "993", proto: "tcp", comment: "IMAPS" }
|
||||||
|
# - { port: "110", proto: "tcp", comment: "POP3" } # Disabled non-TLS
|
||||||
|
- { port: "995", proto: "tcp", comment: "POP3S" }
|
||||||
|
- { port: "4190", proto: "tcp", comment: "Sieve" }
|
||||||
|
when:
|
||||||
|
- ansible_facts['os_family'] == "Debian"
|
||||||
|
- ufw_check.rc == 0
|
||||||
|
|
||||||
|
- name: Create systemd service for Mailcow
|
||||||
|
template:
|
||||||
|
src: mailcow.service.j2
|
||||||
|
dest: /etc/systemd/system/mailcow.service
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart mailcow
|
||||||
|
|
||||||
|
- name: Enable Mailcow service
|
||||||
|
systemd:
|
||||||
|
name: mailcow
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
# Caddy not needed - Mailcow includes nginx for SSL termination
|
||||||
43
ansible/roles/mailcow/templates/Caddyfile.j2
Normal file
43
ansible/roles/mailcow/templates/Caddyfile.j2
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
# Global options
|
||||||
|
admin off
|
||||||
|
persist_config off
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mailcow web interface
|
||||||
|
mail.w5isp.com {
|
||||||
|
reverse_proxy http://127.0.0.1:{{ mailcow_http_port }} {
|
||||||
|
header_up Host {host}
|
||||||
|
header_up X-Real-IP {remote}
|
||||||
|
header_up X-Forwarded-For {remote}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Autodiscover/Autoconfig for w5isp.com
|
||||||
|
autodiscover.w5isp.com {
|
||||||
|
reverse_proxy http://127.0.0.1:{{ mailcow_http_port }}
|
||||||
|
}
|
||||||
|
|
||||||
|
autoconfig.w5isp.com {
|
||||||
|
reverse_proxy http://127.0.0.1:{{ mailcow_http_port }}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mailcow web interface for mcintire.me
|
||||||
|
mail.mcintire.me {
|
||||||
|
reverse_proxy http://127.0.0.1:{{ mailcow_http_port }} {
|
||||||
|
header_up Host {host}
|
||||||
|
header_up X-Real-IP {remote}
|
||||||
|
header_up X-Forwarded-For {remote}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Autodiscover/Autoconfig for mcintire.me
|
||||||
|
autodiscover.mcintire.me {
|
||||||
|
reverse_proxy http://127.0.0.1:{{ mailcow_http_port }}
|
||||||
|
}
|
||||||
|
|
||||||
|
autoconfig.mcintire.me {
|
||||||
|
reverse_proxy http://127.0.0.1:{{ mailcow_http_port }}
|
||||||
|
}
|
||||||
37
ansible/roles/mailcow/templates/caddy-mailcow.conf.j2
Normal file
37
ansible/roles/mailcow/templates/caddy-mailcow.conf.j2
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Mailcow reverse proxy configuration for Caddy
|
||||||
|
mail.w5isp.com {
|
||||||
|
reverse_proxy localhost:{{ mailcow_http_port }} {
|
||||||
|
header_up Host {host}
|
||||||
|
header_up X-Real-IP {remote}
|
||||||
|
header_up X-Forwarded-For {remote}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Redirect for autodiscover
|
||||||
|
autodiscover.w5isp.com {
|
||||||
|
reverse_proxy localhost:{{ mailcow_http_port }}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Redirect for autoconfig
|
||||||
|
autoconfig.w5isp.com {
|
||||||
|
reverse_proxy localhost:{{ mailcow_http_port }}
|
||||||
|
}
|
||||||
|
|
||||||
|
# For mcintire.me domain
|
||||||
|
mail.mcintire.me {
|
||||||
|
reverse_proxy localhost:{{ mailcow_http_port }} {
|
||||||
|
header_up Host {host}
|
||||||
|
header_up X-Real-IP {remote}
|
||||||
|
header_up X-Forwarded-For {remote}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
autodiscover.mcintire.me {
|
||||||
|
reverse_proxy localhost:{{ mailcow_http_port }}
|
||||||
|
}
|
||||||
|
|
||||||
|
autoconfig.mcintire.me {
|
||||||
|
reverse_proxy localhost:{{ mailcow_http_port }}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
services:
|
||||||
|
nginx-mailcow:
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=false"
|
||||||
|
|
||||||
|
postfix-mailcow:
|
||||||
|
ports:
|
||||||
|
- "0.0.0.0:{{ mailcow_smtp_port }}:25"
|
||||||
|
- "0.0.0.0:{{ mailcow_submission_port }}:587"
|
||||||
|
- "0.0.0.0:{{ mailcow_smtps_port }}:465"
|
||||||
|
|
||||||
|
dovecot-mailcow:
|
||||||
|
ports:
|
||||||
|
# - "0.0.0.0:{{ mailcow_imap_port }}:143" # Disabled non-TLS IMAP
|
||||||
|
- "0.0.0.0:{{ mailcow_imaps_port }}:993"
|
||||||
|
# - "0.0.0.0:{{ mailcow_pop3_port }}:110" # Disabled non-TLS POP3
|
||||||
|
- "0.0.0.0:{{ mailcow_pop3s_port }}:995"
|
||||||
|
- "0.0.0.0:4190:4190"
|
||||||
64
ansible/roles/mailcow/templates/mailcow.conf.j2
Normal file
64
ansible/roles/mailcow/templates/mailcow.conf.j2
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
# ------------------------------
|
||||||
|
# Mailcow configuration
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
# Your mail server hostname
|
||||||
|
MAILCOW_HOSTNAME={{ mailcow_hostname }}
|
||||||
|
|
||||||
|
# Your timezone
|
||||||
|
TZ={{ mailcow_timezone }}
|
||||||
|
|
||||||
|
# Fixed project name
|
||||||
|
COMPOSE_PROJECT_NAME={{ mailcow_compose_project_name }}
|
||||||
|
|
||||||
|
# Database configuration
|
||||||
|
DBNAME={{ mailcow_dbname }}
|
||||||
|
DBUSER={{ mailcow_dbuser }}
|
||||||
|
DBPASS={{ mailcow_dbpass }}
|
||||||
|
DBROOT={{ mailcow_dbroot }}
|
||||||
|
|
||||||
|
# Redis configuration
|
||||||
|
REDISPASS={{ mailcow_redispass | default(vault_mailcow_redispass) }}
|
||||||
|
|
||||||
|
# HTTP/HTTPS bindings
|
||||||
|
HTTP_BIND={{ mailcow_http_bind }}
|
||||||
|
HTTP_PORT={{ mailcow_http_port }}
|
||||||
|
HTTPS_BIND={{ mailcow_https_bind }}
|
||||||
|
HTTPS_PORT={{ mailcow_https_port }}
|
||||||
|
|
||||||
|
# Mail port bindings
|
||||||
|
SMTP_PORT={{ mailcow_smtp_port }}
|
||||||
|
SMTPS_PORT={{ mailcow_smtps_port }}
|
||||||
|
SUBMISSION_PORT={{ mailcow_submission_port }}
|
||||||
|
IMAP_PORT={{ mailcow_imap_port }}
|
||||||
|
IMAPS_PORT={{ mailcow_imaps_port }}
|
||||||
|
POP_PORT={{ mailcow_pop3_port }}
|
||||||
|
POPS_PORT={{ mailcow_pop3s_port }}
|
||||||
|
SIEVE_PORT=4190
|
||||||
|
|
||||||
|
# API configuration
|
||||||
|
API_KEY={{ mailcow_api_key }}
|
||||||
|
API_ALLOW_FROM={{ mailcow_api_allow_ips }}
|
||||||
|
|
||||||
|
# Skip various components
|
||||||
|
SKIP_LETS_ENCRYPT={{ mailcow_skip_lets_encrypt }}
|
||||||
|
SKIP_SOGO={{ mailcow_skip_sogo }}
|
||||||
|
SKIP_CLAMD={{ mailcow_skip_clamd }}
|
||||||
|
SKIP_SOLR={{ mailcow_skip_solr }}
|
||||||
|
|
||||||
|
# Additional SAN for certificate
|
||||||
|
ADDITIONAL_SAN={{ mailcow_additional_san }}
|
||||||
|
|
||||||
|
# Watchdog configuration
|
||||||
|
WATCHDOG_NOTIFY_EMAIL=
|
||||||
|
WATCHDOG_NOTIFY_BAN=n
|
||||||
|
WATCHDOG_SUBJECT="Watchdog ALERT"
|
||||||
|
|
||||||
|
# Other settings
|
||||||
|
MAILDIR_GC_TIME=7200
|
||||||
|
ADDITIONAL_SERVER_NAMES=
|
||||||
|
ACME_CONTACT=
|
||||||
|
|
||||||
|
# Docker settings
|
||||||
|
DOCKER_COMPOSE_VERSION=native
|
||||||
|
|
||||||
17
ansible/roles/mailcow/templates/mailcow.service.j2
Normal file
17
ansible/roles/mailcow/templates/mailcow.service.j2
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Mailcow dockerized mail server
|
||||||
|
After=docker.service
|
||||||
|
Requires=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
WorkingDirectory={{ mailcow_base_path }}
|
||||||
|
ExecStart=/usr/bin/docker-compose up -d
|
||||||
|
ExecStop=/usr/bin/docker-compose down
|
||||||
|
ExecReload=/usr/bin/docker-compose restart
|
||||||
|
User=mailcow
|
||||||
|
Group=docker
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
6
ansible/roles/syncthing/handlers/main.yml
Normal file
6
ansible/roles/syncthing/handlers/main.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
- name: restart syncthing
|
||||||
|
systemd:
|
||||||
|
name: syncthing@graham
|
||||||
|
state: restarted
|
||||||
|
daemon_reload: yes
|
||||||
132
ansible/roles/syncthing/tasks/main.yml
Normal file
132
ansible/roles/syncthing/tasks/main.yml
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
---
|
||||||
|
# Install and configure Syncthing
|
||||||
|
|
||||||
|
- name: Install required packages
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- apt-transport-https
|
||||||
|
- curl
|
||||||
|
- gnupg2
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Add Syncthing GPG key
|
||||||
|
get_url:
|
||||||
|
url: "https://syncthing.net/release-key.gpg"
|
||||||
|
dest: /usr/share/keyrings/syncthing-archive-keyring.gpg
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Add Syncthing repository
|
||||||
|
apt_repository:
|
||||||
|
repo: "deb [signed-by=/usr/share/keyrings/syncthing-archive-keyring.gpg] https://apt.syncthing.net/ syncthing stable"
|
||||||
|
state: present
|
||||||
|
filename: syncthing
|
||||||
|
|
||||||
|
- name: Install Syncthing
|
||||||
|
apt:
|
||||||
|
name: syncthing
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Ensure graham user exists
|
||||||
|
user:
|
||||||
|
name: graham
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create Syncthing configuration directory
|
||||||
|
file:
|
||||||
|
path: /home/graham/.config/syncthing
|
||||||
|
state: directory
|
||||||
|
owner: graham
|
||||||
|
group: graham
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Deploy Syncthing configuration
|
||||||
|
template:
|
||||||
|
src: config.xml.j2
|
||||||
|
dest: /home/graham/.config/syncthing/config.xml
|
||||||
|
owner: graham
|
||||||
|
group: graham
|
||||||
|
mode: '0600'
|
||||||
|
backup: yes
|
||||||
|
notify: restart syncthing
|
||||||
|
|
||||||
|
- name: Create Syncthing systemd service
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
[Unit]
|
||||||
|
Description=Syncthing - Open Source Continuous File Synchronization
|
||||||
|
Documentation=man:syncthing(1)
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=graham
|
||||||
|
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
SuccessExitStatus=3 4
|
||||||
|
RestartForceExitStatus=3 4
|
||||||
|
|
||||||
|
# Hardening
|
||||||
|
SystemCallArchitectures=native
|
||||||
|
MemoryDenyWriteExecute=true
|
||||||
|
NoNewPrivileges=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
dest: /etc/systemd/system/syncthing@graham.service
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart syncthing
|
||||||
|
|
||||||
|
- name: Stop old syncthing service if exists
|
||||||
|
systemd:
|
||||||
|
name: syncthing@syncthing
|
||||||
|
state: stopped
|
||||||
|
enabled: no
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Enable and start Syncthing service
|
||||||
|
systemd:
|
||||||
|
name: syncthing@graham
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Check if ufw is installed
|
||||||
|
command: which ufw
|
||||||
|
register: ufw_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Configure firewall for Syncthing web UI
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: '8384'
|
||||||
|
proto: tcp
|
||||||
|
comment: 'Syncthing Web UI'
|
||||||
|
when:
|
||||||
|
- ansible_facts['os_family'] == "Debian"
|
||||||
|
- ufw_check.rc == 0
|
||||||
|
|
||||||
|
- name: Configure firewall for Syncthing sync protocol
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: '22000'
|
||||||
|
proto: tcp
|
||||||
|
comment: 'Syncthing Sync Protocol'
|
||||||
|
when:
|
||||||
|
- ansible_facts['os_family'] == "Debian"
|
||||||
|
- ufw_check.rc == 0
|
||||||
|
|
||||||
|
- name: Configure firewall for Syncthing discovery
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: '21027'
|
||||||
|
proto: udp
|
||||||
|
comment: 'Syncthing Local Discovery'
|
||||||
|
when:
|
||||||
|
- ansible_facts['os_family'] == "Debian"
|
||||||
|
- ufw_check.rc == 0
|
||||||
57
ansible/roles/syncthing/templates/config.xml.j2
Normal file
57
ansible/roles/syncthing/templates/config.xml.j2
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
<configuration version="37">
|
||||||
|
<gui enabled="true" tls="false" debugging="false">
|
||||||
|
<address>0.0.0.0:8384</address>
|
||||||
|
<apikey></apikey>
|
||||||
|
<theme>default</theme>
|
||||||
|
</gui>
|
||||||
|
<options>
|
||||||
|
<listenAddress>default</listenAddress>
|
||||||
|
<globalAnnounceServer>default</globalAnnounceServer>
|
||||||
|
<globalAnnounceEnabled>true</globalAnnounceEnabled>
|
||||||
|
<localAnnounceEnabled>true</localAnnounceEnabled>
|
||||||
|
<localAnnouncePort>21027</localAnnouncePort>
|
||||||
|
<localAnnounceMCAddr>[ff12::8384]:21027</localAnnounceMCAddr>
|
||||||
|
<maxSendKbps>0</maxSendKbps>
|
||||||
|
<maxRecvKbps>0</maxRecvKbps>
|
||||||
|
<reconnectionIntervalS>60</reconnectionIntervalS>
|
||||||
|
<relaysEnabled>true</relaysEnabled>
|
||||||
|
<relayReconnectIntervalM>10</relayReconnectIntervalM>
|
||||||
|
<startBrowser>false</startBrowser>
|
||||||
|
<natEnabled>true</natEnabled>
|
||||||
|
<natLeaseMinutes>60</natLeaseMinutes>
|
||||||
|
<natRenewalMinutes>30</natRenewalMinutes>
|
||||||
|
<natTimeoutSeconds>10</natTimeoutSeconds>
|
||||||
|
<urAccepted>-1</urAccepted>
|
||||||
|
<urSeen>3</urSeen>
|
||||||
|
<urURL>https://data.syncthing.net/newdata</urURL>
|
||||||
|
<urPostInsecurely>false</urPostInsecurely>
|
||||||
|
<urInitialDelayS>1800</urInitialDelayS>
|
||||||
|
<restartOnWakeup>true</restartOnWakeup>
|
||||||
|
<autoUpgradeIntervalH>12</autoUpgradeIntervalH>
|
||||||
|
<upgradeToPreReleases>false</upgradeToPreReleases>
|
||||||
|
<keepTemporariesH>24</keepTemporariesH>
|
||||||
|
<cacheIgnoredFiles>false</cacheIgnoredFiles>
|
||||||
|
<progressUpdateIntervalS>5</progressUpdateIntervalS>
|
||||||
|
<limitBandwidthInLan>false</limitBandwidthInLan>
|
||||||
|
<minHomeDiskFree unit="%">1</minHomeDiskFree>
|
||||||
|
<releasesURL>https://upgrades.syncthing.net/meta.json</releasesURL>
|
||||||
|
<overwriteRemoteDeviceNamesOnConnect>false</overwriteRemoteDeviceNamesOnConnect>
|
||||||
|
<tempIndexMinBlocks>10</tempIndexMinBlocks>
|
||||||
|
<unackedNotificationIDs></unackedNotificationIDs>
|
||||||
|
<trafficClass>0</trafficClass>
|
||||||
|
<setLowPriority>true</setLowPriority>
|
||||||
|
<maxFolderConcurrency>0</maxFolderConcurrency>
|
||||||
|
<crashReportingURL>https://crash.syncthing.net/newcrash</crashReportingURL>
|
||||||
|
<crashReportingEnabled>true</crashReportingEnabled>
|
||||||
|
<stunKeepaliveStartS>180</stunKeepaliveStartS>
|
||||||
|
<stunKeepaliveMinS>20</stunKeepaliveMinS>
|
||||||
|
<stunServers>default</stunServers>
|
||||||
|
<databaseTuning>auto</databaseTuning>
|
||||||
|
<maxConcurrentIncomingRequestKiB>0</maxConcurrentIncomingRequestKiB>
|
||||||
|
<announceLANAddresses>true</announceLANAddresses>
|
||||||
|
<sendFullIndexOnUpgrade>false</sendFullIndexOnUpgrade>
|
||||||
|
<connectionLimitEnough>0</connectionLimitEnough>
|
||||||
|
<connectionLimitMax>0</connectionLimitMax>
|
||||||
|
<insecureAllowOldTLSVersions>false</insecureAllowOldTLSVersions>
|
||||||
|
</options>
|
||||||
|
</configuration>
|
||||||
111
home/ansible/create-mariadb-container.yml
Normal file
111
home/ansible/create-mariadb-container.yml
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
---
|
||||||
|
- name: Create MariaDB LXC Container
|
||||||
|
hosts: lab02
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
ct_id: 301
|
||||||
|
ct_name: mariadb
|
||||||
|
ct_template: "local:vztmpl/debian-13-standard_13.1-1_amd64.tar.zst"
|
||||||
|
ct_memory: 2048 # 2GB RAM
|
||||||
|
ct_disk_size: 50 # 50GB storage
|
||||||
|
ct_cores: 2
|
||||||
|
ct_ip: "10.0.19.6/22"
|
||||||
|
ct_gateway: "10.0.19.254"
|
||||||
|
ct_storage: "ceph" # Use Ceph RBD storage
|
||||||
|
mariadb_root_password: "dOtPgrVnkIW1zwfjvW9rSw"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create MariaDB LXC container
|
||||||
|
command: |
|
||||||
|
pct create {{ ct_id }} {{ ct_template }} \
|
||||||
|
--hostname {{ ct_name }} \
|
||||||
|
--memory {{ ct_memory }} \
|
||||||
|
--cores {{ ct_cores }} \
|
||||||
|
--net0 name=eth0,bridge=vmbr0,ip={{ ct_ip }},gw={{ ct_gateway }} \
|
||||||
|
--storage {{ ct_storage }} \
|
||||||
|
--rootfs {{ ct_storage }}:{{ ct_disk_size }} \
|
||||||
|
--unprivileged 1 \
|
||||||
|
--features nesting=1 \
|
||||||
|
--onboot 1 \
|
||||||
|
--startup order=20
|
||||||
|
|
||||||
|
- name: Start container
|
||||||
|
command: pct start {{ ct_id }}
|
||||||
|
|
||||||
|
- name: Wait for container to boot
|
||||||
|
pause:
|
||||||
|
seconds: 30
|
||||||
|
|
||||||
|
- name: Update container packages
|
||||||
|
shell: pct exec {{ ct_id }} -- apt update && pct exec {{ ct_id }} -- apt upgrade -y
|
||||||
|
|
||||||
|
- name: Install MariaDB
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- bash -c "
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get install -y mariadb-server mariadb-client
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: Start and enable MariaDB
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- bash -c "
|
||||||
|
systemctl enable mariadb
|
||||||
|
systemctl start mariadb
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: Configure MariaDB for network access
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- bash -c "
|
||||||
|
# Update bind-address
|
||||||
|
sed -i 's/^bind-address.*=.*/bind-address = 0.0.0.0/' /etc/mysql/mariadb.conf.d/50-server.cnf
|
||||||
|
|
||||||
|
# Set root password and configure access
|
||||||
|
mysql -u root << 'EOF'
|
||||||
|
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('{{ mariadb_root_password }}');
|
||||||
|
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '{{ mariadb_root_password }}';
|
||||||
|
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Restart MariaDB
|
||||||
|
systemctl restart mariadb
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: Save credentials to file
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
MariaDB Container Credentials
|
||||||
|
=============================
|
||||||
|
Container ID: {{ ct_id }}
|
||||||
|
Host: lab02
|
||||||
|
IP Address: 10.0.19.6
|
||||||
|
Port: 3306
|
||||||
|
|
||||||
|
Root Credentials:
|
||||||
|
Username: root
|
||||||
|
Password: {{ mariadb_root_password }}
|
||||||
|
|
||||||
|
Connection String:
|
||||||
|
mysql -h 10.0.19.6 -u root -p'{{ mariadb_root_password }}'
|
||||||
|
|
||||||
|
Note: This container was created on {{ ansible_date_time.iso8601 }}
|
||||||
|
dest: "./mariadb_credentials.txt"
|
||||||
|
mode: '0600'
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Display connection info
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
MariaDB container created successfully!
|
||||||
|
|
||||||
|
Container details:
|
||||||
|
- Container ID: {{ ct_id }}
|
||||||
|
- Host: lab02
|
||||||
|
- IP: 10.0.19.6
|
||||||
|
- Storage: {{ ct_disk_size }}GB on {{ ct_storage }}
|
||||||
|
|
||||||
|
Root credentials:
|
||||||
|
- Username: root
|
||||||
|
- Password: {{ mariadb_root_password }}
|
||||||
|
|
||||||
|
Credentials saved to: ./mariadb_credentials.txt
|
||||||
35
home/ansible/fix-k3s-dns.yml
Normal file
35
home/ansible/fix-k3s-dns.yml
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
- name: Fix DNS on K3s Nodes
|
||||||
|
hosts: k3s_cluster
|
||||||
|
become: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Update resolv.conf to use Quad9 DNS
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
nameserver 9.9.9.9
|
||||||
|
nameserver 149.112.112.112
|
||||||
|
dest: /etc/resolv.conf
|
||||||
|
backup: yes
|
||||||
|
|
||||||
|
- name: Ensure systemd-resolved is not managing resolv.conf
|
||||||
|
systemd:
|
||||||
|
name: systemd-resolved
|
||||||
|
state: stopped
|
||||||
|
enabled: no
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Test DNS resolution
|
||||||
|
command: nslookup registry-1.docker.io
|
||||||
|
register: dns_test
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Show DNS test results
|
||||||
|
debug:
|
||||||
|
msg: "{{ dns_test.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Restart containerd to pick up DNS changes
|
||||||
|
systemd:
|
||||||
|
name: containerd
|
||||||
|
state: restarted
|
||||||
|
when: inventory_hostname in groups['k3s_cluster']
|
||||||
23
home/ansible/mariadb_all_credentials.txt
Normal file
23
home/ansible/mariadb_all_credentials.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
MariaDB Container Credentials
|
||||||
|
=============================
|
||||||
|
Created: 2025-09-12
|
||||||
|
|
||||||
|
Container Details:
|
||||||
|
- Container ID: 301
|
||||||
|
- Host: lab02
|
||||||
|
- IP Address: 10.0.19.6
|
||||||
|
- Port: 3306
|
||||||
|
|
||||||
|
Root Credentials:
|
||||||
|
- Username: root
|
||||||
|
- Password: dOtPgrVnkIW1zwfjvW9rSw
|
||||||
|
- Connection: mysql -h 10.0.19.6 -u root -p'dOtPgrVnkIW1zwfjvW9rSw'
|
||||||
|
|
||||||
|
Wavelog Database:
|
||||||
|
- Database: wavelog
|
||||||
|
- Username: wavelog
|
||||||
|
- Password: m4icNmGTRtOMgrNxsxEdrw
|
||||||
|
- Connection: mysql -h 10.0.19.6 -u wavelog -p'm4icNmGTRtOMgrNxsxEdrw' wavelog
|
||||||
|
|
||||||
|
Kubernetes Secret:
|
||||||
|
kubectl create secret generic wavelog-db-secret --from-literal=password="m4icNmGTRtOMgrNxsxEdrw" -n wavelog
|
||||||
31
home/ansible/restart-k3s-services.yml
Normal file
31
home/ansible/restart-k3s-services.yml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
- name: Restart K3s Services After DNS Fix
|
||||||
|
hosts: k3s_cluster
|
||||||
|
become: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Test DNS resolution using getent
|
||||||
|
command: getent hosts registry-1.docker.io
|
||||||
|
register: dns_test
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Show DNS test results
|
||||||
|
debug:
|
||||||
|
msg: "{{ dns_test.stdout | default('DNS resolution failed') }}"
|
||||||
|
|
||||||
|
- name: Restart K3s service on control nodes
|
||||||
|
systemd:
|
||||||
|
name: k3s
|
||||||
|
state: restarted
|
||||||
|
when: inventory_hostname in groups['k3s_control_plane']
|
||||||
|
|
||||||
|
- name: Restart K3s agent on worker nodes
|
||||||
|
systemd:
|
||||||
|
name: k3s-agent
|
||||||
|
state: restarted
|
||||||
|
when: inventory_hostname in groups['k3s_workers']
|
||||||
|
|
||||||
|
- name: Wait for services to stabilize
|
||||||
|
pause:
|
||||||
|
seconds: 30
|
||||||
123
home/ansible/setup-mariadb-container.yml
Normal file
123
home/ansible/setup-mariadb-container.yml
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
---
|
||||||
|
- name: Setup MariaDB in Container
|
||||||
|
hosts: lab02
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
ct_id: 301
|
||||||
|
mariadb_root_password: "dOtPgrVnkIW1zwfjvW9rSw"
|
||||||
|
wavelog_password: "m4icNmGTRtOMgrNxsxEdrw"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Configure DNS in container
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- bash -c "echo 'nameserver 9.9.9.9' > /etc/resolv.conf"
|
||||||
|
|
||||||
|
- name: Update container packages
|
||||||
|
shell: pct exec {{ ct_id }} -- apt-get update
|
||||||
|
register: apt_update
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
until: apt_update.rc == 0
|
||||||
|
|
||||||
|
- name: Install MariaDB Server
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- bash -c "
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get install -y mariadb-server mariadb-client
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: Start and enable MariaDB
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- systemctl enable mariadb
|
||||||
|
pct exec {{ ct_id }} -- systemctl start mariadb
|
||||||
|
|
||||||
|
- name: Secure MariaDB installation
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- bash -c "mysql -u root << 'EOF'
|
||||||
|
-- Set root password
|
||||||
|
ALTER USER 'root'@'localhost' IDENTIFIED BY '{{ mariadb_root_password }}';
|
||||||
|
|
||||||
|
-- Create root user for remote access
|
||||||
|
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '{{ mariadb_root_password }}';
|
||||||
|
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
|
||||||
|
|
||||||
|
-- Remove anonymous users
|
||||||
|
DELETE FROM mysql.user WHERE User='';
|
||||||
|
|
||||||
|
-- Remove test database
|
||||||
|
DROP DATABASE IF EXISTS test;
|
||||||
|
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
|
||||||
|
|
||||||
|
-- Reload privileges
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
EOF"
|
||||||
|
|
||||||
|
- name: Configure MariaDB for network access
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- sed -i 's/^bind-address.*=.*/bind-address = 0.0.0.0/' /etc/mysql/mariadb.conf.d/50-server.cnf
|
||||||
|
pct exec {{ ct_id }} -- systemctl restart mariadb
|
||||||
|
|
||||||
|
- name: Create Wavelog database and user
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- mysql -u root -p'{{ mariadb_root_password }}' << 'EOF'
|
||||||
|
CREATE DATABASE IF NOT EXISTS wavelog CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
CREATE USER IF NOT EXISTS 'wavelog'@'%' IDENTIFIED BY '{{ wavelog_password }}';
|
||||||
|
GRANT ALL PRIVILEGES ON wavelog.* TO 'wavelog'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Test database connections
|
||||||
|
shell: |
|
||||||
|
pct exec {{ ct_id }} -- mysql -u root -p'{{ mariadb_root_password }}' -e "SELECT VERSION();"
|
||||||
|
pct exec {{ ct_id }} -- mysql -u wavelog -p'{{ wavelog_password }}' wavelog -e "SELECT DATABASE();"
|
||||||
|
register: db_test
|
||||||
|
|
||||||
|
- name: Save all credentials
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
MariaDB Container Credentials
|
||||||
|
=============================
|
||||||
|
Created: {{ ansible_date_time.iso8601 }}
|
||||||
|
|
||||||
|
Container Details:
|
||||||
|
- Container ID: {{ ct_id }}
|
||||||
|
- Host: lab02
|
||||||
|
- IP Address: 10.0.19.6
|
||||||
|
- Port: 3306
|
||||||
|
|
||||||
|
Root Credentials:
|
||||||
|
- Username: root
|
||||||
|
- Password: {{ mariadb_root_password }}
|
||||||
|
- Connection: mysql -h 10.0.19.6 -u root -p'{{ mariadb_root_password }}'
|
||||||
|
|
||||||
|
Wavelog Database:
|
||||||
|
- Database: wavelog
|
||||||
|
- Username: wavelog
|
||||||
|
- Password: {{ wavelog_password }}
|
||||||
|
- Connection: mysql -h 10.0.19.6 -u wavelog -p'{{ wavelog_password }}' wavelog
|
||||||
|
|
||||||
|
Test Results:
|
||||||
|
{{ db_test.stdout }}
|
||||||
|
dest: "./mariadb_all_credentials.txt"
|
||||||
|
mode: '0600'
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Update Kubernetes secret for Wavelog
|
||||||
|
shell: |
|
||||||
|
kubectl create secret generic wavelog-db-secret \
|
||||||
|
--from-literal=password="{{ wavelog_password }}" \
|
||||||
|
--dry-run=client -o yaml | kubectl apply -f - -n wavelog
|
||||||
|
environment:
|
||||||
|
KUBECONFIG: "{{ playbook_dir }}/kubeconfig"
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Display summary
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
MariaDB setup completed successfully!
|
||||||
|
|
||||||
|
Root password: {{ mariadb_root_password }}
|
||||||
|
Wavelog password: {{ wavelog_password }}
|
||||||
|
|
||||||
|
All credentials saved to: ./mariadb_all_credentials.txt
|
||||||
|
Kubernetes secret updated: wavelog-db-secret
|
||||||
47
home/ansible/setup-wavelog-db.yml
Normal file
47
home/ansible/setup-wavelog-db.yml
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
---
|
||||||
|
- name: Setup Wavelog Database in MariaDB
|
||||||
|
hosts: lab02
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
mysql_container_id: 301
|
||||||
|
wavelog_password: "m4icNmGTRtOMgrNxsxEdrw"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create Wavelog database and user
|
||||||
|
shell: |
|
||||||
|
pct exec {{ mysql_container_id }} -- bash -c "mysql -u root <<EOF
|
||||||
|
CREATE DATABASE IF NOT EXISTS wavelog;
|
||||||
|
CREATE USER IF NOT EXISTS 'wavelog'@'%' IDENTIFIED BY '{{ wavelog_password }}';
|
||||||
|
GRANT ALL PRIVILEGES ON wavelog.* TO 'wavelog'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
EOF"
|
||||||
|
register: db_creation
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: If root needs password, try with socket authentication
|
||||||
|
shell: |
|
||||||
|
pct exec {{ mysql_container_id }} -- bash -c "mysql <<EOF
|
||||||
|
CREATE DATABASE IF NOT EXISTS wavelog;
|
||||||
|
CREATE USER IF NOT EXISTS 'wavelog'@'%' IDENTIFIED BY '{{ wavelog_password }}';
|
||||||
|
GRANT ALL PRIVILEGES ON wavelog.* TO 'wavelog'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
EOF"
|
||||||
|
when: db_creation.rc != 0
|
||||||
|
|
||||||
|
- name: Test Wavelog database connection
|
||||||
|
shell: |
|
||||||
|
pct exec {{ mysql_container_id }} -- mysql -u wavelog -p'{{ wavelog_password }}' -e "SELECT DATABASE();" wavelog
|
||||||
|
register: test_result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Display result
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
Database setup completed!
|
||||||
|
Host: 10.0.19.6
|
||||||
|
Port: 3306
|
||||||
|
Database: wavelog
|
||||||
|
Username: wavelog
|
||||||
|
Password: {{ wavelog_password }}
|
||||||
|
|
||||||
|
Test result: {{ test_result.stdout | default('Failed to connect') }}
|
||||||
68
home/ansible/wavelog-deployment.yml
Normal file
68
home/ansible/wavelog-deployment.yml
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: wavelog
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: wavelog
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: wavelog
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: wavelog
|
||||||
|
image: ghcr.io/wavelog/wavelog:latest
|
||||||
|
env:
|
||||||
|
- name: CI_ENV
|
||||||
|
value: "docker"
|
||||||
|
- name: WAVELOG_DB_HOST
|
||||||
|
value: "10.0.19.6"
|
||||||
|
- name: WAVELOG_DB_PORT
|
||||||
|
value: "3306"
|
||||||
|
- name: WAVELOG_DB_NAME
|
||||||
|
value: "wavelog"
|
||||||
|
- name: WAVELOG_DB_USER
|
||||||
|
value: "wavelog"
|
||||||
|
- name: WAVELOG_DB_PASS
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: wavelog-db-secret
|
||||||
|
key: password
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /var/www/html/application/config/docker
|
||||||
|
- name: uploads
|
||||||
|
mountPath: /var/www/html/uploads
|
||||||
|
- name: userdata
|
||||||
|
mountPath: /var/www/html/userdata
|
||||||
|
- name: backup
|
||||||
|
mountPath: /var/www/html/backup
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: ghcr-pull-secret
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-config
|
||||||
|
- name: uploads
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-uploads
|
||||||
|
- name: userdata
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-userdata
|
||||||
|
- name: backup
|
||||||
|
emptyDir: {}
|
||||||
89
home/ansible/wavelog-final.yml
Normal file
89
home/ansible/wavelog-final.yml
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: wavelog
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: wavelog
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: wavelog
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: wavelog
|
||||||
|
image: php:8.2-apache
|
||||||
|
env:
|
||||||
|
- name: DATABASE_HOST
|
||||||
|
value: "10.0.19.6"
|
||||||
|
- name: DATABASE_PORT
|
||||||
|
value: "3306"
|
||||||
|
- name: DATABASE_NAME
|
||||||
|
value: "wavelog"
|
||||||
|
- name: DATABASE_USER
|
||||||
|
value: "wavelog"
|
||||||
|
- name: DATABASE_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: wavelog-db-secret
|
||||||
|
key: password
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/www/html
|
||||||
|
lifecycle:
|
||||||
|
postStart:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
# Install dependencies if not already installed
|
||||||
|
if [ ! -f /var/www/html/.deps_installed ]; then
|
||||||
|
apt-get update && apt-get install -y \
|
||||||
|
git \
|
||||||
|
unzip \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-dev \
|
||||||
|
libfreetype6-dev \
|
||||||
|
libzip-dev \
|
||||||
|
libicu-dev \
|
||||||
|
mariadb-client \
|
||||||
|
curl \
|
||||||
|
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||||
|
&& docker-php-ext-install gd mysqli pdo pdo_mysql zip intl \
|
||||||
|
&& a2enmod rewrite \
|
||||||
|
&& touch /var/www/html/.deps_installed
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clone Wavelog if not exists
|
||||||
|
if [ ! -f /var/www/html/index.php ]; then
|
||||||
|
cd /tmp
|
||||||
|
git clone https://github.com/wavelog/wavelog.git
|
||||||
|
cp -R wavelog/* /var/www/html/
|
||||||
|
cp -R wavelog/.* /var/www/html/ 2>/dev/null || true
|
||||||
|
chown -R www-data:www-data /var/www/html
|
||||||
|
chmod -R 755 /var/www/html
|
||||||
|
|
||||||
|
# Create uploads directory
|
||||||
|
mkdir -p /var/www/html/uploads
|
||||||
|
chown -R www-data:www-data /var/www/html/uploads
|
||||||
|
chmod -R 777 /var/www/html/uploads
|
||||||
|
fi
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-data
|
||||||
133
home/ansible/wavelog-k8s.yml
Normal file
133
home/ansible/wavelog-k8s.yml
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: wavelog-uploads
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: wavelog-userdata
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: wavelog-config
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: wavelog
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: wavelog
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: wavelog
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: wavelog
|
||||||
|
image: ghcr.io/wavelog/wavelog:latest
|
||||||
|
env:
|
||||||
|
- name: CI_ENV
|
||||||
|
value: "docker"
|
||||||
|
- name: DB_HOST
|
||||||
|
value: "10.0.19.6"
|
||||||
|
- name: DB_NAME
|
||||||
|
value: "wavelog"
|
||||||
|
- name: DB_USER
|
||||||
|
value: "wavelog"
|
||||||
|
- name: DB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: wavelog-db-secret
|
||||||
|
key: password
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /var/www/html/application/config/docker
|
||||||
|
- name: uploads
|
||||||
|
mountPath: /var/www/html/uploads
|
||||||
|
- name: userdata
|
||||||
|
mountPath: /var/www/html/userdata
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: ghcr-pull-secret
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-config
|
||||||
|
- name: uploads
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-uploads
|
||||||
|
- name: userdata
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-userdata
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: wavelog
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: wavelog
|
||||||
|
type: LoadBalancer
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
name: http
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: wavelog-tailscale
|
||||||
|
namespace: wavelog
|
||||||
|
annotations:
|
||||||
|
tailscale.com/expose: "true"
|
||||||
|
tailscale.com/hostname: "wavelog"
|
||||||
|
tailscale.com/funnel: "false"
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: wavelog
|
||||||
|
type: LoadBalancer
|
||||||
|
loadBalancerClass: tailscale
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
name: http
|
||||||
68
home/ansible/wavelog-official.yml
Normal file
68
home/ansible/wavelog-official.yml
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: wavelog
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: wavelog
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: wavelog
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: wavelog
|
||||||
|
image: ghcr.io/wavelog/wavelog:latest
|
||||||
|
env:
|
||||||
|
- name: CI_ENV
|
||||||
|
value: "docker"
|
||||||
|
- name: WAVELOG_DB_HOST
|
||||||
|
value: "10.0.19.6"
|
||||||
|
- name: WAVELOG_DB_PORT
|
||||||
|
value: "3306"
|
||||||
|
- name: WAVELOG_DB_NAME
|
||||||
|
value: "wavelog"
|
||||||
|
- name: WAVELOG_DB_USER
|
||||||
|
value: "wavelog"
|
||||||
|
- name: WAVELOG_DB_PASS
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: wavelog-db-secret
|
||||||
|
key: password
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /var/www/html/application/config/docker
|
||||||
|
- name: uploads
|
||||||
|
mountPath: /var/www/html/uploads
|
||||||
|
- name: userdata
|
||||||
|
mountPath: /var/www/html/userdata
|
||||||
|
- name: backup
|
||||||
|
mountPath: /var/www/html/backup
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: ghcr-pull-secret
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-config
|
||||||
|
- name: uploads
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-uploads
|
||||||
|
- name: userdata
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-userdata
|
||||||
|
- name: backup
|
||||||
|
emptyDir: {}
|
||||||
108
home/ansible/wavelog-simple-deployment.yml
Normal file
108
home/ansible/wavelog-simple-deployment.yml
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: wavelog
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: wavelog
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: wavelog
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- name: setup
|
||||||
|
image: php:8.2-apache
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
echo "Installing dependencies..."
|
||||||
|
apt-get update && apt-get install -y \
|
||||||
|
git unzip libpng-dev libjpeg-dev libfreetype6-dev \
|
||||||
|
libzip-dev libicu-dev mariadb-client curl \
|
||||||
|
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||||
|
&& docker-php-ext-install gd mysqli pdo pdo_mysql zip intl
|
||||||
|
|
||||||
|
echo "Cloning Wavelog..."
|
||||||
|
cd /tmp
|
||||||
|
git clone https://github.com/wavelog/wavelog.git
|
||||||
|
cp -R wavelog/* /var/www/html/
|
||||||
|
cp -R wavelog/.* /var/www/html/ 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create config directory
|
||||||
|
mkdir -p /var/www/html/application/config/docker
|
||||||
|
|
||||||
|
# Create database.php config
|
||||||
|
cat > /var/www/html/application/config/database.php << 'EOF'
|
||||||
|
<?php
|
||||||
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||||
|
|
||||||
|
$active_group = 'default';
|
||||||
|
$query_builder = TRUE;
|
||||||
|
|
||||||
|
$db['default'] = array(
|
||||||
|
'dsn' => '',
|
||||||
|
'hostname' => '10.0.19.6',
|
||||||
|
'username' => 'wavelog',
|
||||||
|
'password' => 'm4icNmGTRtOMgrNxsxEdrw',
|
||||||
|
'database' => 'wavelog',
|
||||||
|
'dbdriver' => 'mysqli',
|
||||||
|
'dbprefix' => '',
|
||||||
|
'pconnect' => FALSE,
|
||||||
|
'db_debug' => FALSE,
|
||||||
|
'cache_on' => FALSE,
|
||||||
|
'cachedir' => '',
|
||||||
|
'char_set' => 'utf8mb4',
|
||||||
|
'dbcollat' => 'utf8mb4_general_ci',
|
||||||
|
'swap_pre' => '',
|
||||||
|
'encrypt' => FALSE,
|
||||||
|
'compress' => FALSE,
|
||||||
|
'stricton' => FALSE,
|
||||||
|
'failover' => array(),
|
||||||
|
'save_queries' => TRUE
|
||||||
|
);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
chown -R www-data:www-data /var/www/html
|
||||||
|
chmod -R 755 /var/www/html
|
||||||
|
chmod -R 777 /var/www/html/uploads
|
||||||
|
chmod -R 777 /var/www/html/application/cache
|
||||||
|
chmod -R 777 /var/www/html/application/logs
|
||||||
|
chmod -R 777 /var/www/html/userdata
|
||||||
|
|
||||||
|
# Enable Apache rewrite module
|
||||||
|
a2enmod rewrite
|
||||||
|
|
||||||
|
echo "Setup complete!"
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/www/html
|
||||||
|
containers:
|
||||||
|
- name: wavelog
|
||||||
|
image: php:8.2-apache
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/www/html
|
||||||
|
env:
|
||||||
|
- name: APACHE_DOCUMENT_ROOT
|
||||||
|
value: /var/www/html
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-data
|
||||||
109
home/ansible/wavelog-simple.yml
Normal file
109
home/ansible/wavelog-simple.yml
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: wavelog
|
||||||
|
namespace: wavelog
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: wavelog
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: wavelog
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: wavelog
|
||||||
|
image: php:8.2-apache
|
||||||
|
env:
|
||||||
|
- name: CI_ENV
|
||||||
|
value: "production"
|
||||||
|
- name: DB_HOST
|
||||||
|
value: "10.0.19.6"
|
||||||
|
- name: DB_NAME
|
||||||
|
value: "wavelog"
|
||||||
|
- name: DB_USER
|
||||||
|
value: "wavelog"
|
||||||
|
- name: DB_PASS
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: wavelog-db-secret
|
||||||
|
key: password
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/www/html
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
# Install dependencies
|
||||||
|
apt-get update && apt-get install -y \
|
||||||
|
git \
|
||||||
|
unzip \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-dev \
|
||||||
|
libfreetype6-dev \
|
||||||
|
libzip-dev \
|
||||||
|
libicu-dev \
|
||||||
|
mariadb-client \
|
||||||
|
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||||
|
&& docker-php-ext-install gd mysqli pdo pdo_mysql zip intl \
|
||||||
|
&& a2enmod rewrite
|
||||||
|
|
||||||
|
# Clone Wavelog if not exists
|
||||||
|
if [ ! -d /var/www/html/index.php ]; then
|
||||||
|
cd /tmp
|
||||||
|
git clone https://github.com/wavelog/wavelog.git
|
||||||
|
cp -R wavelog/* /var/www/html/
|
||||||
|
chown -R www-data:www-data /var/www/html
|
||||||
|
|
||||||
|
# Create database config
|
||||||
|
cat > /var/www/html/application/config/database.php << EOF
|
||||||
|
<?php
|
||||||
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||||
|
|
||||||
|
\$active_group = 'default';
|
||||||
|
\$query_builder = TRUE;
|
||||||
|
|
||||||
|
\$db['default'] = array(
|
||||||
|
'dsn' => '',
|
||||||
|
'hostname' => '${DB_HOST}',
|
||||||
|
'username' => '${DB_USER}',
|
||||||
|
'password' => '${DB_PASS}',
|
||||||
|
'database' => '${DB_NAME}',
|
||||||
|
'dbdriver' => 'mysqli',
|
||||||
|
'dbprefix' => '',
|
||||||
|
'pconnect' => FALSE,
|
||||||
|
'db_debug' => (ENVIRONMENT !== 'production'),
|
||||||
|
'cache_on' => FALSE,
|
||||||
|
'cachedir' => '',
|
||||||
|
'char_set' => 'utf8mb4',
|
||||||
|
'dbcollat' => 'utf8mb4_general_ci',
|
||||||
|
'swap_pre' => '',
|
||||||
|
'encrypt' => FALSE,
|
||||||
|
'compress' => FALSE,
|
||||||
|
'stricton' => FALSE,
|
||||||
|
'failover' => array(),
|
||||||
|
'save_queries' => TRUE
|
||||||
|
);
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start Apache
|
||||||
|
apache2-foreground
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: wavelog-data
|
||||||
15
home/ansible/wavelog_db_credentials.txt
Normal file
15
home/ansible/wavelog_db_credentials.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
Wavelog Database Credentials
|
||||||
|
============================
|
||||||
|
|
||||||
|
MariaDB Container: 301 on lab02
|
||||||
|
Host: 10.0.19.6
|
||||||
|
Port: 3306
|
||||||
|
Database: wavelog
|
||||||
|
Username: wavelog
|
||||||
|
Password: m4icNmGTRtOMgrNxsxEdrw
|
||||||
|
|
||||||
|
Note: Database needs to be created manually in MariaDB container 301.
|
||||||
|
The root password for MariaDB may be required.
|
||||||
|
|
||||||
|
Connection String:
|
||||||
|
mysql://wavelog:m4icNmGTRtOMgrNxsxEdrw@10.0.19.6:3306/wavelog
|
||||||
82
home/cluster-380/README.md
Normal file
82
home/cluster-380/README.md
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Cluster-380 (w5isp.w5isp.com)
|
||||||
|
|
||||||
|
Single-node K3s cluster with Traefik ingress and automatic SSL.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **Server**: w5isp.w5isp.com (204.110.191.200)
|
||||||
|
- **OS**: Debian 13
|
||||||
|
- **K3s**: Single-node cluster with Traefik enabled
|
||||||
|
- **Ingress**: Traefik with Let's Encrypt automatic SSL
|
||||||
|
- **Storage**: Longhorn distributed storage
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. **Deploy the server** and install K3s using Ansible:
|
||||||
|
```bash
|
||||||
|
cd ansible
|
||||||
|
ansible-playbook -l w5isp.w5isp.com general.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Deploy infrastructure components**:
|
||||||
|
```bash
|
||||||
|
cd home/cluster-380/infrastructure
|
||||||
|
./deploy-with-traefik.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Deploy applications**:
|
||||||
|
```bash
|
||||||
|
kubectl apply -f ../apps/forgejo-traefik.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
### Traefik (Ingress Controller)
|
||||||
|
- Handles all HTTP/HTTPS traffic on port 80/443
|
||||||
|
- Automatic SSL certificates via Let's Encrypt
|
||||||
|
- Can handle TCP routing (e.g., SSH for Forgejo on port 2222)
|
||||||
|
|
||||||
|
### Example Application: Forgejo
|
||||||
|
- URL: https://git.w5isp.com
|
||||||
|
- SSH: git.w5isp.com:2222
|
||||||
|
- Automatic SSL certificate
|
||||||
|
|
||||||
|
## Adding New Services
|
||||||
|
|
||||||
|
Create an IngressRoute for automatic SSL:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: myapp
|
||||||
|
namespace: myapp
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`myapp.w5isp.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: myapp
|
||||||
|
port: 80
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
```
|
||||||
|
|
||||||
|
For TCP services:
|
||||||
|
```yaml
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: myapp-tcp
|
||||||
|
namespace: myapp
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- myapp-tcp # Define in traefik-config.yaml
|
||||||
|
routes:
|
||||||
|
- match: HostSNI(`*`)
|
||||||
|
services:
|
||||||
|
- name: myapp-tcp
|
||||||
|
port: 1234
|
||||||
|
```
|
||||||
148
home/cluster-380/apps/forgejo-traefik.yaml
Normal file
148
home/cluster-380/apps/forgejo-traefik.yaml
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
# Forgejo deployment with Traefik ingress
|
||||||
|
---
|
||||||
|
# Namespace
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: forgejo
|
||||||
|
---
|
||||||
|
# PVC for Forgejo data using Longhorn
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: forgejo-data
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: longhorn
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 50Gi
|
||||||
|
---
|
||||||
|
# Main Forgejo Deployment
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: forgejo
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: forgejo
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: forgejo
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
containers:
|
||||||
|
- name: forgejo
|
||||||
|
image: codeberg.org/forgejo/forgejo:1.21-rootless
|
||||||
|
ports:
|
||||||
|
- containerPort: 3000
|
||||||
|
name: http
|
||||||
|
- containerPort: 2222
|
||||||
|
name: ssh
|
||||||
|
env:
|
||||||
|
- name: USER_UID
|
||||||
|
value: "1000"
|
||||||
|
- name: USER_GID
|
||||||
|
value: "1000"
|
||||||
|
- name: FORGEJO__database__DB_TYPE
|
||||||
|
value: sqlite3
|
||||||
|
- name: FORGEJO__server__ROOT_URL
|
||||||
|
value: https://git.w5isp.com/
|
||||||
|
- name: FORGEJO__server__DOMAIN
|
||||||
|
value: git.w5isp.com
|
||||||
|
- name: FORGEJO__server__SSH_DOMAIN
|
||||||
|
value: git.w5isp.com
|
||||||
|
- name: FORGEJO__server__SSH_PORT
|
||||||
|
value: "2222"
|
||||||
|
- name: FORGEJO__DEFAULT__APP_NAME
|
||||||
|
value: "W5ISP Git"
|
||||||
|
- name: FORGEJO__server__OFFLINE_MODE
|
||||||
|
value: "false"
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: forgejo-data
|
||||||
|
---
|
||||||
|
# Service for HTTP/HTTPS
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: forgejo-http
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: forgejo
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 3000
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
# Service for SSH (direct TCP routing)
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: forgejo-ssh
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: forgejo
|
||||||
|
ports:
|
||||||
|
- name: ssh
|
||||||
|
port: 2222
|
||||||
|
targetPort: 2222
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
# IngressRoute for HTTPS with automatic SSL
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: forgejo
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`git.w5isp.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: forgejo-http
|
||||||
|
port: 80
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
---
|
||||||
|
# IngressRouteTCP for SSH
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: forgejo-ssh
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- ssh-forgejo
|
||||||
|
routes:
|
||||||
|
- match: HostSNI(`*`)
|
||||||
|
services:
|
||||||
|
- name: forgejo-ssh
|
||||||
|
port: 2222
|
||||||
127
home/cluster-380/apps/forgejo.yaml
Normal file
127
home/cluster-380/apps/forgejo.yaml
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
# Complete Forgejo deployment for cluster-380
|
||||||
|
---
|
||||||
|
# Namespace
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: forgejo
|
||||||
|
---
|
||||||
|
# PVC for Forgejo data using Longhorn
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: forgejo-data
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: longhorn
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 50Gi
|
||||||
|
---
|
||||||
|
# Main Forgejo Deployment
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: forgejo
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: forgejo
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: forgejo
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
containers:
|
||||||
|
- name: forgejo
|
||||||
|
image: codeberg.org/forgejo/forgejo:1.21-rootless
|
||||||
|
ports:
|
||||||
|
- containerPort: 3000
|
||||||
|
name: http
|
||||||
|
- containerPort: 2222
|
||||||
|
name: ssh
|
||||||
|
env:
|
||||||
|
- name: USER_UID
|
||||||
|
value: "1000"
|
||||||
|
- name: USER_GID
|
||||||
|
value: "1000"
|
||||||
|
- name: FORGEJO__database__DB_TYPE
|
||||||
|
value: sqlite3
|
||||||
|
- name: FORGEJO__server__ROOT_URL
|
||||||
|
value: https://git.w5isp.com/
|
||||||
|
- name: FORGEJO__server__DOMAIN
|
||||||
|
value: git.w5isp.com
|
||||||
|
- name: FORGEJO__server__SSH_DOMAIN
|
||||||
|
value: git.w5isp.com
|
||||||
|
- name: FORGEJO__DEFAULT__APP_NAME
|
||||||
|
value: "W5ISP Git"
|
||||||
|
- name: FORGEJO__server__OFFLINE_MODE
|
||||||
|
value: "false"
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: forgejo-data
|
||||||
|
---
|
||||||
|
# Service for LoadBalancer
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: forgejo
|
||||||
|
namespace: forgejo
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
selector:
|
||||||
|
app: forgejo
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 3000
|
||||||
|
protocol: TCP
|
||||||
|
- name: ssh
|
||||||
|
port: 22
|
||||||
|
targetPort: 2222
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
# Ingress for HTTPS access
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: forgejo
|
||||||
|
namespace: forgejo
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- git.w5isp.com
|
||||||
|
secretName: forgejo-tls
|
||||||
|
rules:
|
||||||
|
- host: git.w5isp.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: forgejo
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
24
home/cluster-380/infrastructure/deploy-with-traefik.sh
Executable file
24
home/cluster-380/infrastructure/deploy-with-traefik.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Deploy script for cluster-380 with Traefik ingress
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Deploying system namespaces..."
|
||||||
|
kubectl apply -f ../system/namespaces.yaml
|
||||||
|
|
||||||
|
echo "Configuring Traefik..."
|
||||||
|
kubectl apply -f ../system/traefik-config.yaml
|
||||||
|
|
||||||
|
echo "Waiting for Traefik to be ready..."
|
||||||
|
kubectl -n kube-system wait --for=condition=ready pod -l app.kubernetes.io/name=traefik --timeout=90s
|
||||||
|
|
||||||
|
echo "Installing Longhorn v1.5.3..."
|
||||||
|
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.5.3/deploy/longhorn.yaml
|
||||||
|
|
||||||
|
echo "Waiting for Longhorn to be ready..."
|
||||||
|
kubectl -n longhorn-system wait --for=condition=ready pod -l app=longhorn-manager --timeout=180s
|
||||||
|
|
||||||
|
echo "Infrastructure components deployed successfully!"
|
||||||
|
echo ""
|
||||||
|
echo "You can now deploy applications using Traefik IngressRoutes for automatic SSL"
|
||||||
|
echo "Example: kubectl apply -f ../apps/forgejo-traefik.yaml"
|
||||||
27
home/cluster-380/infrastructure/deploy.sh
Executable file
27
home/cluster-380/infrastructure/deploy.sh
Executable file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Deploy script for cluster-380 infrastructure components
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Deploying system namespaces..."
|
||||||
|
kubectl apply -f ../system/namespaces.yaml
|
||||||
|
|
||||||
|
echo "Installing MetalLB v0.13.12..."
|
||||||
|
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml
|
||||||
|
|
||||||
|
echo "Waiting for MetalLB to be ready..."
|
||||||
|
kubectl -n metallb-system wait --for=condition=ready pod -l app=metallb --timeout=90s
|
||||||
|
|
||||||
|
echo "Applying MetalLB configuration..."
|
||||||
|
kubectl apply -f ../system/metallb-config.yaml
|
||||||
|
|
||||||
|
echo "Installing Longhorn v1.5.3..."
|
||||||
|
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.5.3/deploy/longhorn.yaml
|
||||||
|
|
||||||
|
echo "Installing cert-manager v1.13.3..."
|
||||||
|
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
|
||||||
|
|
||||||
|
echo "Waiting for cert-manager to be ready..."
|
||||||
|
kubectl -n cert-manager wait --for=condition=ready pod -l app.kubernetes.io/instance=cert-manager --timeout=90s
|
||||||
|
|
||||||
|
echo "Infrastructure components deployed successfully!"
|
||||||
18
home/cluster-380/system/metallb-config.yaml
Normal file
18
home/cluster-380/system/metallb-config.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
apiVersion: metallb.io/v1beta1
|
||||||
|
kind: IPAddressPool
|
||||||
|
metadata:
|
||||||
|
name: default-pool
|
||||||
|
namespace: metallb-system
|
||||||
|
spec:
|
||||||
|
addresses:
|
||||||
|
- 204.110.191.200/32 # Using the single server IP for LoadBalancer services
|
||||||
|
---
|
||||||
|
apiVersion: metallb.io/v1beta1
|
||||||
|
kind: L2Advertisement
|
||||||
|
metadata:
|
||||||
|
name: default-advertisement
|
||||||
|
namespace: metallb-system
|
||||||
|
spec:
|
||||||
|
ipAddressPools:
|
||||||
|
- default-pool
|
||||||
33
home/cluster-380/system/namespaces.yaml
Normal file
33
home/cluster-380/system/namespaces.yaml
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: metallb-system
|
||||||
|
labels:
|
||||||
|
pod-security.kubernetes.io/enforce: privileged
|
||||||
|
pod-security.kubernetes.io/warn: privileged
|
||||||
|
pod-security.kubernetes.io/audit: privileged
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: longhorn-system
|
||||||
|
labels:
|
||||||
|
pod-security.kubernetes.io/enforce: privileged
|
||||||
|
pod-security.kubernetes.io/warn: privileged
|
||||||
|
pod-security.kubernetes.io/audit: privileged
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: cert-manager
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: ingress-system
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: monitoring
|
||||||
95
home/cluster-380/system/traefik-config.yaml
Normal file
95
home/cluster-380/system/traefik-config.yaml
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
---
|
||||||
|
# Traefik configuration for automatic SSL
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: traefik-config
|
||||||
|
namespace: kube-system
|
||||||
|
data:
|
||||||
|
traefik.yaml: |
|
||||||
|
global:
|
||||||
|
checkNewVersion: false
|
||||||
|
sendAnonymousUsage: false
|
||||||
|
|
||||||
|
api:
|
||||||
|
dashboard: true
|
||||||
|
debug: false
|
||||||
|
|
||||||
|
entryPoints:
|
||||||
|
web:
|
||||||
|
address: ":80"
|
||||||
|
http:
|
||||||
|
redirections:
|
||||||
|
entrypoint:
|
||||||
|
to: websecure
|
||||||
|
scheme: https
|
||||||
|
websecure:
|
||||||
|
address: ":443"
|
||||||
|
ssh-forgejo:
|
||||||
|
address: ":2222/tcp"
|
||||||
|
|
||||||
|
providers:
|
||||||
|
kubernetesIngress:
|
||||||
|
allowCrossNamespace: true
|
||||||
|
publishedService:
|
||||||
|
enabled: true
|
||||||
|
name: "kube-system/traefik"
|
||||||
|
kubernetesCRD:
|
||||||
|
allowCrossNamespace: true
|
||||||
|
|
||||||
|
certificatesResolvers:
|
||||||
|
letsencrypt:
|
||||||
|
acme:
|
||||||
|
email: postmaster@w5isp.com
|
||||||
|
storage: /data/acme.json
|
||||||
|
httpChallenge:
|
||||||
|
entryPoint: web
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: INFO
|
||||||
|
---
|
||||||
|
# HelmChartConfig to apply Traefik configuration
|
||||||
|
apiVersion: helm.cattle.io/v1
|
||||||
|
kind: HelmChartConfig
|
||||||
|
metadata:
|
||||||
|
name: traefik
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
valuesContent: |-
|
||||||
|
deployment:
|
||||||
|
kind: DaemonSet
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: LoadBalancer
|
||||||
|
spec:
|
||||||
|
loadBalancerIP: 204.110.191.200
|
||||||
|
|
||||||
|
ports:
|
||||||
|
web:
|
||||||
|
port: 80
|
||||||
|
expose: true
|
||||||
|
exposedPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
websecure:
|
||||||
|
port: 443
|
||||||
|
expose: true
|
||||||
|
exposedPort: 443
|
||||||
|
protocol: TCP
|
||||||
|
ssh-forgejo:
|
||||||
|
port: 2222
|
||||||
|
expose: true
|
||||||
|
exposedPort: 2222
|
||||||
|
protocol: TCP
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: longhorn
|
||||||
|
size: 1Gi
|
||||||
|
|
||||||
|
additionalArguments:
|
||||||
|
- "--configfile=/config/traefik.yaml"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: traefik-config
|
||||||
|
mountPath: /config
|
||||||
|
type: configMap
|
||||||
|
|
@ -1,36 +1,59 @@
|
||||||
resource "dnsimple_zone_record" "mcintire_mx_10" {
|
# Commented out ProtonMail MX records - now using Mailcow
|
||||||
|
# resource "dnsimple_zone_record" "mcintire_mx_10" {
|
||||||
|
# zone_name = "mcintire.me"
|
||||||
|
# name = "@"
|
||||||
|
# value = "mail.protonmail.ch."
|
||||||
|
# type = "MX"
|
||||||
|
# ttl = 3600
|
||||||
|
# priority = 10
|
||||||
|
# }
|
||||||
|
|
||||||
|
# resource "dnsimple_zone_record" "mcintire_mx_20" {
|
||||||
|
# zone_name = "mcintire.me"
|
||||||
|
# name = "@"
|
||||||
|
# value = "mailsec.protonmail.ch."
|
||||||
|
# type = "MX"
|
||||||
|
# ttl = 3600
|
||||||
|
# priority = 20
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Mailcow MX record
|
||||||
|
resource "dnsimple_zone_record" "mcintire_mx_mailcow" {
|
||||||
zone_name = "mcintire.me"
|
zone_name = "mcintire.me"
|
||||||
name = "@"
|
name = ""
|
||||||
value = "mail.protonmail.ch."
|
|
||||||
type = "MX"
|
|
||||||
ttl = 3600
|
|
||||||
priority = 10
|
priority = 10
|
||||||
}
|
value = "mail.w5isp.com"
|
||||||
|
|
||||||
resource "dnsimple_zone_record" "mcintire_mx_20" {
|
|
||||||
zone_name = "mcintire.me"
|
|
||||||
name = "@"
|
|
||||||
value = "mailsec.protonmail.ch."
|
|
||||||
type = "MX"
|
type = "MX"
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
priority = 20
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "dnsimple_zone_record" "mcintire_txt_spf" {
|
resource "dnsimple_zone_record" "mcintire_mx_backup" {
|
||||||
zone_name = "mcintire.me"
|
zone_name = "mcintire.me"
|
||||||
name = "@"
|
name = ""
|
||||||
value = "v=spf1 include:_spf.protonmail.ch ~all"
|
priority = 20
|
||||||
type = "TXT"
|
value = "mail.nsnw.ca"
|
||||||
|
type = "MX"
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "dnsimple_zone_record" "mcintire_txt_dmarc" {
|
# Commented out ProtonMail SPF record - replaced with Mailcow SPF
|
||||||
zone_name = "mcintire.me"
|
# resource "dnsimple_zone_record" "mcintire_txt_spf" {
|
||||||
name = "_dmarc"
|
# zone_name = "mcintire.me"
|
||||||
value = "v=DMARC1; p=quarantine"
|
# name = "@"
|
||||||
type = "TXT"
|
# value = "v=spf1 include:_spf.protonmail.ch ~all"
|
||||||
}
|
# type = "TXT"
|
||||||
|
# ttl = 3600
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Commented out basic DMARC record - replaced with Mailcow DMARC
|
||||||
|
# resource "dnsimple_zone_record" "mcintire_txt_dmarc" {
|
||||||
|
# zone_name = "mcintire.me"
|
||||||
|
# name = "_dmarc"
|
||||||
|
# value = "v=DMARC1; p=quarantine"
|
||||||
|
# type = "TXT"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Keep ProtonMail verification record for now
|
||||||
resource "dnsimple_zone_record" "mcintire_txt_verification" {
|
resource "dnsimple_zone_record" "mcintire_txt_verification" {
|
||||||
zone_name = "mcintire.me"
|
zone_name = "mcintire.me"
|
||||||
name = "@"
|
name = "@"
|
||||||
|
|
@ -77,3 +100,67 @@ resource "dnsimple_zone_record" "mcintire_cname_test" {
|
||||||
type = "CNAME"
|
type = "CNAME"
|
||||||
ttl = 14400
|
ttl = 14400
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Mail server
|
||||||
|
resource "dnsimple_zone_record" "mcintire_mail" {
|
||||||
|
zone_name = "mcintire.me"
|
||||||
|
name = "mail"
|
||||||
|
value = "204.110.191.216" # sync.w5isp.com - Mailcow server
|
||||||
|
type = "A"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# Autodiscover for mail clients (CNAME to mail server)
|
||||||
|
resource "dnsimple_zone_record" "mcintire_autodiscover" {
|
||||||
|
zone_name = "mcintire.me"
|
||||||
|
name = "autodiscover"
|
||||||
|
value = "mail.w5isp.com"
|
||||||
|
type = "CNAME"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# Autodiscover SRV record
|
||||||
|
resource "dnsimple_zone_record" "mcintire_autodiscover_srv" {
|
||||||
|
zone_name = "mcintire.me"
|
||||||
|
name = "_autodiscover._tcp"
|
||||||
|
value = "0 443 mail.w5isp.com"
|
||||||
|
type = "SRV"
|
||||||
|
priority = 0
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# Autoconfig for mail clients
|
||||||
|
resource "dnsimple_zone_record" "mcintire_autoconfig" {
|
||||||
|
zone_name = "mcintire.me"
|
||||||
|
name = "autoconfig"
|
||||||
|
value = "mail.w5isp.com"
|
||||||
|
type = "CNAME"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# SPF record for Mailcow
|
||||||
|
resource "dnsimple_zone_record" "mcintire_spf_mailcow" {
|
||||||
|
zone_name = "mcintire.me"
|
||||||
|
name = ""
|
||||||
|
value = "v=spf1 mx a ip4:204.110.191.216 ~all"
|
||||||
|
type = "TXT"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# DMARC record for Mailcow
|
||||||
|
resource "dnsimple_zone_record" "mcintire_dmarc_mailcow" {
|
||||||
|
zone_name = "mcintire.me"
|
||||||
|
name = "_dmarc"
|
||||||
|
value = "v=DMARC1; p=quarantine; rua=mailto:postmaster@mcintire.me; ruf=mailto:postmaster@mcintire.me; fo=1"
|
||||||
|
type = "TXT"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# DKIM record from Mailcow
|
||||||
|
resource "dnsimple_zone_record" "mcintire_dkim_mailcow" {
|
||||||
|
zone_name = "mcintire.me"
|
||||||
|
name = "dkim._domainkey"
|
||||||
|
value = "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0rQie7Hz5AmDbVUX+rKNgp6Hf7crtWyfy6qKbqnrxmmernz1rQ6HyOrHhFAlc8nVLNKr8XP2DOROb1jAnrjndZo9I/ymbrrrCBsi9w6zAht2BheijO/R9k5CDRjeSafm6bg0oMKihtNMIdXvEj9ND8hDpZZKxtOrKFH7zLm4CPmm7jf0gqZH2yK+AA3OYUGSYa1OT0LtdMXadk0IVOI2VYf37Hzb3RUvGOYMVkT0xi+23DiyFk7AyCiyv3LQVBMT+/bwyd4k3yVVn2cr9+Nor+HXVjqASLtqcFLMf1SuX0ezSAjBG7BbqQr5G6Jz+n5YglqEIUKVYzJFE7JdDmqQYQIDAQAB"
|
||||||
|
type = "TXT"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ resource "powerdns_record" "ptr_records4" {
|
||||||
for_each = {
|
for_each = {
|
||||||
for i in range(256) : tostring(i) => {
|
for i in range(256) : tostring(i) => {
|
||||||
name = "${i}.191.110.204.in-addr.arpa."
|
name = "${i}.191.110.204.in-addr.arpa."
|
||||||
record = "${i}.191.client.vntx.net."
|
record = tostring(i) == "216" ? "mail.w5isp.com." : "${i}.191.client.vntx.net."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
resource "dnsimple_zone_record" "w5isp_root" {
|
resource "dnsimple_zone_record" "w5isp_root" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = ""
|
name = ""
|
||||||
value = "204.110.191.212" # Points to Caddy proxy server
|
value = "204.110.191.212" # Points to Caddy proxy server
|
||||||
type = "A"
|
type = "A"
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +34,7 @@ resource "dnsimple_zone_record" "w5isp_home" {
|
||||||
resource "dnsimple_zone_record" "w5isp_photos" {
|
resource "dnsimple_zone_record" "w5isp_photos" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = "photos"
|
name = "photos"
|
||||||
value = "204.110.191.212" # Points to Caddy proxy server
|
value = "204.110.191.8"
|
||||||
type = "A"
|
type = "A"
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ resource "dnsimple_zone_record" "w5isp_ntfy" {
|
||||||
resource "dnsimple_zone_record" "w5isp_jellyfin" {
|
resource "dnsimple_zone_record" "w5isp_jellyfin" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = "jellyfin"
|
name = "jellyfin"
|
||||||
value = "204.110.191.212" # Points to Caddy proxy server
|
value = "204.110.191.212" # Points to Caddy proxy server
|
||||||
type = "A"
|
type = "A"
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +66,7 @@ resource "dnsimple_zone_record" "w5isp_jellyfin" {
|
||||||
resource "dnsimple_zone_record" "w5isp_wildcard" {
|
resource "dnsimple_zone_record" "w5isp_wildcard" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = "*"
|
name = "*"
|
||||||
value = "204.110.191.212" # New Caddy proxy server
|
value = "204.110.191.212" # New Caddy proxy server
|
||||||
type = "A"
|
type = "A"
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
@ -83,34 +83,26 @@ resource "dnsimple_zone_record" "w5isp_mx1" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = ""
|
name = ""
|
||||||
priority = 10
|
priority = 10
|
||||||
value = "mail.protonmail.ch"
|
value = "mail.w5isp.com"
|
||||||
type = "MX"
|
type = "MX"
|
||||||
ttl = 36000
|
ttl = 3600
|
||||||
}
|
|
||||||
|
|
||||||
resource "dnsimple_zone_record" "w5isp_mx2" {
|
|
||||||
zone_name = "w5isp.com"
|
|
||||||
name = ""
|
|
||||||
priority = 20
|
|
||||||
value = "mailsec.protonmail.ch"
|
|
||||||
type = "MX"
|
|
||||||
ttl = 36000
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "dnsimple_zone_record" "w5isp_txt" {
|
resource "dnsimple_zone_record" "w5isp_txt" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = ""
|
name = ""
|
||||||
value = "v=spf1 include:_spf.protonmail.ch ~all"
|
value = "v=spf1 mx a ip4:204.110.191.216 ~all"
|
||||||
type = "TXT"
|
type = "TXT"
|
||||||
ttl = 36000
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "dnsimple_zone_record" "w5isp_txt2" {
|
# DKIM record
|
||||||
|
resource "dnsimple_zone_record" "w5isp_dkim" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = ""
|
name = "dkim._domainkey"
|
||||||
value = "protonmail-verification=be3f91ded714b341c2276128270127cb59aa6760"
|
value = "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxti2t8TvzIqKF9BpKn3rQExKg3sS1SyQuwtQgL0r/ELEJ0D9cKU/iM+eB1ROJctKHoMqKDJoRCMP6eibFcgq2kLKqf+aceEOIBx2OK2WCXML+CNqQZA6yO+A8/Jq7iFZPq8D5FmOoxbwRZkso7CkSennSz/+F7nBPI/OfyEiiI4xJzWH3t8SaAkkcy46O+1K0iCkTpsthon7E2PHa3SPkrjbep/5NImTJLK5LuffiLJtLsiK+73mvsAYCDmrNxPTaDjXkj0TWdKl/d/TnlVJl+YloqWIDt/7LtZQM0C7GZ9flIr7z9hHpSWERXAA5Gj5NQ0/hcY3nF4dPoqWs3VeeQIDAQAB"
|
||||||
type = "TXT"
|
type = "TXT"
|
||||||
ttl = 36000
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "dnsimple_zone_record" "w5isp_g" {
|
resource "dnsimple_zone_record" "w5isp_g" {
|
||||||
|
|
@ -153,19 +145,19 @@ resource "dnsimple_zone_record" "w5isp_sendgrid3" {
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "dnsimple_zone_record" "w5isp_sendgrid4" {
|
resource "dnsimple_zone_record" "w5isp_dmarc" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = "_dmarc"
|
name = "_dmarc"
|
||||||
value = "v=DMARC1; p=none;"
|
value = "v=DMARC1; p=quarantine; rua=mailto:postmaster@w5isp.com; ruf=mailto:postmaster@w5isp.com; fo=1"
|
||||||
type = "TXT"
|
type = "TXT"
|
||||||
ttl = 36000
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
# Caddy proxy server
|
# Caddy proxy server
|
||||||
resource "dnsimple_zone_record" "w5isp_caddy" {
|
resource "dnsimple_zone_record" "w5isp_caddy" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = "caddy"
|
name = "caddy"
|
||||||
value = "204.110.191.212" # New Caddy proxy server
|
value = "204.110.191.212" # New Caddy proxy server
|
||||||
type = "A"
|
type = "A"
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
@ -174,8 +166,57 @@ resource "dnsimple_zone_record" "w5isp_caddy" {
|
||||||
resource "dnsimple_zone_record" "w5isp_git" {
|
resource "dnsimple_zone_record" "w5isp_git" {
|
||||||
zone_name = "w5isp.com"
|
zone_name = "w5isp.com"
|
||||||
name = "git"
|
name = "git"
|
||||||
value = "204.110.191.212" # Points to Caddy proxy server
|
value = "204.110.191.212" # Points to Caddy proxy server
|
||||||
type = "A"
|
type = "A"
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Mail server
|
||||||
|
resource "dnsimple_zone_record" "w5isp_mail" {
|
||||||
|
zone_name = "w5isp.com"
|
||||||
|
name = "mail"
|
||||||
|
value = "204.110.191.216" # sync.w5isp.com - Mailcow server
|
||||||
|
type = "A"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# W5ISP server - single-node K3s
|
||||||
|
resource "dnsimple_zone_record" "w5isp_server" {
|
||||||
|
zone_name = "w5isp.com"
|
||||||
|
name = "w5isp"
|
||||||
|
value = "204.110.191.200"
|
||||||
|
type = "A"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# Autodiscover for mail clients
|
||||||
|
resource "dnsimple_zone_record" "w5isp_autodiscover" {
|
||||||
|
zone_name = "w5isp.com"
|
||||||
|
name = "autodiscover"
|
||||||
|
value = "mail.w5isp.com"
|
||||||
|
type = "CNAME"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# Autodiscover SRV record
|
||||||
|
resource "dnsimple_zone_record" "w5isp_autodiscover_srv" {
|
||||||
|
zone_name = "w5isp.com"
|
||||||
|
name = "_autodiscover._tcp"
|
||||||
|
value = "0 443 mail.w5isp.com"
|
||||||
|
type = "SRV"
|
||||||
|
priority = 0
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# Autoconfig for mail clients
|
||||||
|
resource "dnsimple_zone_record" "w5isp_autoconfig" {
|
||||||
|
zone_name = "w5isp.com"
|
||||||
|
name = "autoconfig"
|
||||||
|
value = "mail.w5isp.com"
|
||||||
|
type = "CNAME"
|
||||||
|
ttl = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
# TLSA record for SMTP on port 25 - DNSimple doesn't support TLSA records
|
||||||
|
# You'll need to add this manually through a different DNS provider if needed:
|
||||||
|
# _25._tcp.mail.w5isp.com TLSA 3 1 1 885717a52f0e26cdde481d2d44110c3374ff3b7977626afe2f952b655358308a
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,2 +1,2 @@
|
||||||
token_secret = "1cdd961f-5ee7-4110-8806-e72357a2226f"
|
token_secret = "1cdd961f-5ee7-4110-8806-e72357a2226f"
|
||||||
token_id = "terraform@pve!terraform-token"
|
token_id = "terraform@pve!terraform-token"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue