- Add `hetzner-sizing-report.md` defining data-driven server type recommendations for test and prod environments.
- Update Terraform configurations to align with the recommended `CPX` server types and refine firewall rules for Docker Swarm and database interactions.
- Introduce comprehensive documentation and stack files for:
- Single-node PostgreSQL/MongoDB deployment on a test DB worker node.
- High-availability 3-node MongoDB replica set and Patroni+etcd PostgreSQL cluster for production.
- Enhance Ansible bootstrap roles with SELinux disabling, fail2ban configuration, and StorageBox SSH key management for CI/CD.
- Reorganize and rename setup documentation files for improved structure and clarity.
9.7 KiB
02 - Test Ansible Bootstrap
Bu asamanin amaci Terraform ile olusturulan test makinelerini Linux, hardening, Docker ve Swarm acisindan hazir hale getirmektir. DB yazilimi kurulumu bu asamanin disindadir.
Hedef Makineler
| Host | Rol |
|---|---|
iklim-app-01 |
Swarm manager + app worker |
iklim-db-01 |
Manuel DB kurulumu icin OS-hardening uygulanmis DB node |
Onerilen Dosya Yapisi
ansible/
ansible.cfg
inventory/
generated/
test.yml
group_vars/
all.yml
test.yml
playbooks/
test-bootstrap.yml
roles/
base/
hardening/
docker/
swarm/
node_dirs/
storagebox/
Base Role
Tum test node'larina uygulanir:
dnf update- temel paketler (sirasıyla kurulur):
epel-release— fail2ban ve davfs2 bu repo'dan gelir; once kurulurcurlwgetgitjqtarunzipbash-completiongettext— envsubst icin; CI/CD deploy pipeline'larinda gereklitreeca-certificatesfail2banchronypython3python3-pip
- timezone:
Europe/Istanbul - hostname ayari
- sistem reboot gerekiyorsa kontrollu reboot
Security Hardening Role
Tum test node'larina uygulanir:
- SSH password login kapatilir.
- Root SSH login kapatilir.
- Sadece SSH key ile login kalir.
PermitEmptyPasswords noMaxAuthTries 3fail2banSSH jail aktif edilir.dnf-automaticile otomatik guvenlik guncellestirmeleri aktif edilir.firewallddefault:- incoming: deny (drop zone)
- outgoing: allow
- Public SSH sadece admin CIDR'dan acilir.
SELinux Karari
Rocky Linux 10 SELinux enforcing modda gelir. Karar: disabled.
Gerekce:
- Hetzner Cloud firewall (dis perimeter) + firewalld (host) iki katman ag guvenligini saglar.
- Docker + davfs2 + firewalld kombinasyonu SELinux enforcing modda ek policy ve volume label yonetimi gerektirir.
- Utils VPS'te de disabled yapilmis; tutarlilik saglanir.
# /etc/selinux/config icinde:
SELINUX=disabled
# Degisiklik reboot sonrasi aktif olur
reboot
Ansible'da:
- name: Disable SELinux
ansible.posix.selinux:
state: disabled
register: selinux_change
- name: Reboot if SELinux state changed
ansible.builtin.reboot:
when: selinux_change.changed
fail2ban Konfigurasyonu
/etc/fail2ban/jail.local icerigi:
[DEFAULT]
ignoreip = 127.0.0.1/8 {{ admin_allowed_cidrs }}
bantime = 21600
findtime = 300
maxretry = 5
banaction = iptables-multiport
backend = systemd
[sshd]
enabled = true
bantime: 6 saat banfindtime: 5 dakika icindemaxretry: 5 basarisiz giris → banignoreip: admin CIDR'lari ban'dan muaf tutar
Ansible'da admin_allowed_cidrs listesi space-separated stringe donusturulup template'e basilir.
Not: Docker iptables kurallari firewalld ile etkilesebilir. Hetzner Cloud firewall asil dis perimeter kabul edilir; firewalld host icinde ikinci katman olarak kullanilir.
Docker Role
Sadece iklim-app-01 uzerinde zorunludur. iklim-db-01 uzerinde DB manual kurulum stratejisine gore opsiyonel tutulabilir.
Docker kurulumu resmi Docker dnf repository uzerinden yapilir:
- Docker GPG key + dnf repository (
https://download.docker.com/linux/rhel/docker-ce.repo) - paketler:
docker-cedocker-ce-clicontainerd.iodocker-buildx-plugindocker-compose-plugin
- Docker servisi enabled + started
Docker convenience script kullanilmayacak. Production benzeri test ortami icin paket repository yolu tercih edilir.
Swarm Role
iklim-app-01 uzerinde:
docker swarm init- advertise addr:
10.10.10.11 - data path addr:
10.10.10.11 - overlay network:
iklimco-net- driver:
overlay - attachable:
true
- Node
type=servicelabel'i ile isaretlenir:docker node update --label-add type=service iklim-app-01 - Node
AVAILABILITY=Activekalir (drain edilmez); tek node hem manager hem worker'dir.
Test tek node Swarm oldugu icin join token kullanimi yoktur.
Node Directory Role
iklim-app-01 uzerinde deploy on kosullari:
/opt/iklimco
/opt/iklimco/ssl
/opt/iklimco/init
/opt/iklimco/init/postgresql
/opt/iklimco/init/mongodb
DB node uzerinde manuel DB kurulumu icin minimum:
/opt/iklimco
/opt/iklimco/db
/opt/iklimco/backup
StorageBox DAVFS Mount Role
Her iki node'a uygulanir (iklim-app-01 ve iklim-db-01).
Amac
Hetzner StorageBox'u WebDAV (DAVFS) protokolü üzerinden /mnt/storagebox olarak mount eder. Docker volume'lari bu dizine baglanarak veri kaliciligini ve yedeklemeyi saglar.
Test Ortami Sub-Account
| Parametre | Degisken | Deger |
|---|---|---|
| Ana hesap | storagebox_account |
u469968 |
| Sub-account | storagebox_user |
u469968-sub1 |
| WebDAV URL | storagebox_url |
https://u469968-sub1.your-storagebox.de/ |
| Mount point | storagebox_mount_point |
/mnt/storagebox |
Role Degiskenleri
group_vars/all.yml — tum ortamlar icin ortak:
storagebox_account: "u469968"
group_vars/test.yml — test ortamina ozgu; user ve url account'tan turetilir:
storagebox_user: "{{ storagebox_account }}-sub1"
storagebox_url: "https://{{ storagebox_user }}.your-storagebox.de/"
storagebox_password: "{{ vault_storagebox_password }}" # Ansible Vault ile saklanir
storagebox_mount_point: "/mnt/storagebox"
Prod ortaminda yalnizca suffix degisir (sub1 → sub2), geri kalan her sey turetilir.
vault_storagebox_password degeri Ansible Vault ile sifreli group_vars/test-vault.yml icinde tutulur:
# Sifreleme
ansible-vault encrypt group_vars/test-vault.yml
# Duzenleme
ansible-vault edit group_vars/test-vault.yml
test-vault.yml icerigi:
vault_storagebox_password: "SUB_ACCOUNT_PAROLASI"
Adimlar
-
davfs2 kurulumu
- name: Install davfs2 ansible.builtin.dnf: name: davfs2 state: present -
Kimlik bilgileri dosyasi (
/etc/davfs2/secrets)- name: Configure davfs2 secrets ansible.builtin.lineinfile: path: /etc/davfs2/secrets line: "{{ storagebox_url }} {{ storagebox_user }} {{ storagebox_password }}" create: yes mode: "0600" owner: root group: root -
Mount point olustur
- name: Create mount point ansible.builtin.file: path: "{{ storagebox_mount_point }}" state: directory mode: "0755" -
fstab kaydı
- name: Add fstab entry ansible.builtin.lineinfile: path: /etc/fstab line: >- {{ storagebox_url }} {{ storagebox_mount_point }} davfs _netdev,auto,user,rw,uid=root,gid=root 0 0 state: present -
Mount et
- name: Mount StorageBox ansible.builtin.command: mount {{ storagebox_mount_point }} args: creates: "{{ storagebox_mount_point }}/.mounted_marker"Mount basarisi icin dizine bir marker dosyasi yazilabilir:
- name: Write mount marker ansible.builtin.copy: content: "mounted by ansible" dest: "{{ storagebox_mount_point }}/.mounted_marker"
Notlar
davfs2paketi EPEL repository'sinde bulunur; base roleepel-release'i zaten kurar.- StorageBox sifreleri asla plaintext olarak repository'e eklenmez; Ansible Vault zorunludur.
- Mount noktasi reboot'ta
_netdevflag'i sayesinde network hazir olduktan sonra otomatik mount edilir. - Docker Swarm servisleri
/mnt/storagebox/<env>/<service>/altindaki dizinleri bind mount olarak kullanir.
StorageBox SSH Key Role
Her iki node'a uygulanir (iklim-app-01 ve iklim-db-01).
Amac
Sunucu uzerinde ed25519 SSH anahtar cifti uretilir ve StorageBox ana hesabina yuklenir.
Bu sayede CI/CD pipeline'lari STORAGEBOX_SSH_PRIV Gitea secret'ini kullanarak
sifre girmeden StorageBox'a erisebilir.
Adimlar
-
SSH key uret (eger yoksa)
- name: Generate SSH key for storagebox ansible.builtin.user: name: root generate_ssh_key: yes ssh_key_type: ed25519 ssh_key_file: /root/.ssh/id_ed25519_storagebox ssh_key_comment: "{{ inventory_hostname }}-storagebox" -
Public key'i StorageBox'a yukle
Bu adim manuel yapilir (ilk kez sifre gerektirir):
cat /root/.ssh/id_ed25519_storagebox.pub | ssh -p23 u469968-sub1@u469968-sub1.your-storagebox.de install-ssh-keySonraki erisimler sifresiz calisir:
sftp -P23 u469968-sub1@u469968-sub1.your-storagebox.de -
Private ve public key'leri Gitea'ya ekle
Gitea → Organization Settings → Actions → Secrets:
Secret Adi Deger STORAGEBOX_SSH_PRIV/root/.ssh/id_ed25519_storageboxicerigiSTORAGEBOX_SSH_PUB/root/.ssh/id_ed25519_storagebox.pubicerigiKey icerigini almak icin:
cat /root/.ssh/id_ed25519_storagebox cat /root/.ssh/id_ed25519_storagebox.pub
Notlar
- Her sunucu icin ayri key uretilir; tum public key'ler StorageBox ana hesabina yuklenir.
- Private key asla repo'ya commit edilmez; yalnizca Gitea secret olarak saklanir.
Kabul Kriterleri
ansible -i inventory/generated/test.yml all -m pingbasarili olur.iklim-app-01uzerindedocker infocalisir.iklim-app-01uzerinde Swarm active olur; nodeAVAILABILITY=Active(drain degil).docker network lsicindeiklimco-netgorulur.docker node inspect iklim-app-01 --format '{{.Spec.Labels}}'ciktisimap[type:service]icerir.iklim-db-01uzerinde public DB portu acik degildir.- Public portlar Hetzner firewall + firewalld seviyesinde
22,80,443ile sinirlidir. - Her iki node'da
mount | grep storageboxStorageBox mount'unu gosterir. ls /mnt/storagebox/.mounted_markerbasarili olur.- Reboot sonrasi mount otomatik olarak geri gelir.