Centrálne automatické aktualizácie Docker kontajnerov pomocou Watchtoweru, mTLS a e-mailových notifikácií

Pri väčšom počte Docker hostov začne byť ručné kontrolovanie nových image pomerne otravné. Na jednom serveri beží monitoring, na inom mailové služby, inde vlastné aplikácie a postupne sa z jednoduchého prostredia stáva infraštruktúra, kde treba mať aktualizácie pod kontrolou.

Cieľom tejto dokumentácie je ukázať, ako som nasadil centrálne riadený Watchtower, ktorý automaticky aktualizuje iba vybrané Docker kontajnery na vzdialených hostoch.

1. Návrh riešenia a architektúra

Riešenie som navrhol tak, aby Watchtower:

  • bežal centrálne na jednom serveri,
  • pristupoval k vzdialeným Docker daemon-om cez zabezpečené mTLS spojenie,
  • aktualizoval iba explicitne povolené kontajnery,
  • neposielal zbytočné notifikácie pri každej kontrole,
  • poslal e-mail pri úspešnom update alebo chybe,
  • nezasahoval do kritických služieb ako databázy, Mailcow, FreeIPA alebo ďalšie infraštruktúrne komponenty.

Použitá architektúra vyzerá nasledovne:

Na serveri 10.10.8.6 teda bežia dve nezávislé Watchtower inštancie:

watchtower-84
watchtower-85

Každá z nich sa pripája k jednému konkrétnemu Docker hostu.

Prvá spravuje:

10.10.8.4

Druhá spravuje:

10.10.8.5

čiže logika je:

Výhodou tohto riešenia je, že na vzdialených serveroch nemusí bežať ďalší Watchtower kontajner. Centrálne miesto zároveň umožňuje jednoduchšie spravovať certifikáty, notifikácie a harmonogram aktualizácií.

Prečo nepoužiť Docker API bez TLS

Docker daemon je veľmi privilegovaná služba. Klient, ktorý má plný prístup k Docker API, môže vytvárať kontajnery, mountovať filesystem hosta a v praxi tým môže získať veľmi vysoké oprávnenia na danom serveri.

Preto som nepoužil nezabezpečený Docker API endpoint:

tcp://10.10.8.4:2375

Namiesto toho používam:

tcp://10.10.8.4:2376
tcp://10.10.8.5:2376

s mTLS autentifikáciou.

Pri mTLS sa neoveruje iba server voči klientovi, ale aj klient voči serveru.

To znamená, že samotná znalosť IP adresy a portu nestačí.

Bez správneho klientského certifikátu Docker spojenie odmietne.

Pri teste bez klientského certifikátu sme dostali:

tlsv13 alert certificate required

a pri použití správneho certifikátu:

OK

To je presne stav, ktorý chceme.

Prečo nepovoliť automatické aktualizácie všetkého

Watchtower vie veľmi jednoducho aktualizovať všetky kontajnery, ale pri produkčnom alebo domácom infra prostredí to podľa mňa nie je dobrý prístup.

Niektoré služby môžu pri novej verzii:

meniť databázovú schému,
vyžadovať migráciu,
meniť formát konfigurácie,
meniť API,
vyžadovať koordinovaný upgrade viacerých komponentov.

Preto používam label-only režim.

Watchtower aktualizuje iba kontajnery, ktoré majú explicitne:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

V mojom prípade sú automaticky aktualizované napríklad:

Element
ChangeDetection
Browserless Chrome
Grafana

Naopak automaticky neaktualizujem:

Mailcow
Synapse
Zabbix
MariaDB
PostgreSQL
Passbolt
NetBox
FreePBX
FreeIPA
vlastné kontajnery

Pri týchto službách preferujem klasický postup:

backup
kontrola release notes
ručný update
kontrola aplikácie

To je bezpečnejšie a dáva väčšiu kontrolu nad prípadnými migráciami alebo zmenami.

E-mailové notifikácie

Súčasťou riešenia sú aj e-mailové notifikácie.

Watchtower odosiela správy cez SMTP účet:

updater@ibasterisk.eu

Používa sa samostatný App Password s povoleným iba SMTP protokolom.

Komunikácia prebieha cez:

SMTP port 587
STARTTLS

Heslo nie je uložené priamo v docker-compose.yml, ale v samostatnom súbore s prístupom iba pre root.

Watchtower neposiela mail pri každej nočnej kontrole.

Správa sa odošle iba vtedy, keď:

sa kontajner aktualizuje
alebo
update skončí chybou

Tým sa zabráni zbytočnému spamu.

2. Vytvorenie vlastnej Docker CA a certifikátov pre mTLS

Pre zabezpečenú komunikáciu medzi centrálnym Watchtower serverom a vzdialenými Docker daemonmi som použil vlastnú certifikačnú autoritu určenú výhradne pre Docker API.

Certifikáty vytváram centrálne na serveri:

10.10.8.6
freeipa.ibasterisk.local

Docker CA bude následne podpisovať:

serverový certifikát pre 10.10.8.4
serverový certifikát pre 10.10.8.5
klientsky certifikát pre Watchtower

Architektúra certifikátov teda vyzerá nasledovne:

Vďaka tomu Docker daemon vie overiť, že prichádzajúci klient je skutočne náš Watchtower, a Watchtower zároveň overí identitu vzdialeného Docker servera.

Vytvorenie adresára pre PKI

Na serveri 10.10.8.6 som vytvoril samostatný adresár:

sudo mkdir -p /etc/watchtower-pki
sudo chmod 700 /etc/watchtower-pki

Následne som prešiel do root shellu:

sudo -i
cd /etc/watchtower-pki

Obsah tohto adresára je dostupný iba používateľovi root.

Vytvorenie Docker CA

Najskôr som vytvoril privátny kľúč certifikačnej autority:

openssl genrsa -out docker-ca-key.pem 4096

Potom samotný CA certifikát:

openssl req \
  -new \
  -x509 \
  -days 3650 \
  -key docker-ca-key.pem \
  -sha256 \
  -out docker-ca.pem \
  -subj "/CN=iBasterisk Docker CA"

CA je platná desať rokov. Privátny kľúč CA je najcitlivejší súbor v celom riešení.

Nastavil som preto práva:

chmod 400 docker-ca-key.pem
chmod 444 docker-ca.pem

Privátny kľúč:

docker-ca-key.pem

zostáva iba na 10.10.8.6.

Na vzdialené Docker servery sa nikdy nekopíruje.

Serverový certifikát pre Docker host 10.10.8.4

Pre prvý Docker host som vytvoril samostatný privátny kľúč:

openssl genrsa -out docker-10.10.8.4-key.pem 4096
openssl req \
  -subj "/CN=10.10.8.4" \
  -sha256 \
  -new \
  -key docker-10.10.8.4-key.pem \
  -out docker-10.10.8.4.csr

Samotné CN však pri modernom TLS nestačí. Certifikát musí obsahovať správny Subject Alternative Name.

Preto som vytvoril:

cat > docker-10.10.8.4-ext.cnf <<'EOF'
subjectAltName = IP:10.10.8.4,DNS:mail-ibasterisk
extendedKeyUsage = serverAuth
EOF

Certifikát som následne podpísal Docker CA:

openssl x509 \
  -req \
  -days 825 \
  -sha256 \
  -in docker-10.10.8.4.csr \
  -CA docker-ca.pem \
  -CAkey docker-ca-key.pem \
  -CAcreateserial \
  -out docker-10.10.8.4-cert.pem \
  -extfile docker-10.10.8.4-ext.cnf

Dôležitá je najmä hodnota:

extendedKeyUsage = serverAuth

Tým explicitne určujeme, že certifikát slúži na autentifikáciu TLS servera.

Výsledok som overil:

openssl x509 \
  -in docker-10.10.8.4-cert.pem \
  -noout \
  -subject \
  -issuer \
  -dates \
  -ext subjectAltName \
  -ext extendedKeyUsage

Výstup obsahoval:

subject=CN = 10.10.8.4
issuer=CN = iBasterisk Docker CA

a:

IP Address:10.10.8.4
DNS:mail-ibasterisk

plus:

TLS Web Server Authentication

SAN som si ešte samostatne overil:

openssl x509 \
  -in docker-10.10.8.4-cert.pem \
  -noout -text | grep -A2 "Subject Alternative Name"

Výsledok:

X509v3 Subject Alternative Name:
    IP Address:10.10.8.4, DNS:mail-ibasterisk

Serverový certifikát pre Docker host 10.10.8.5

Rovnakým spôsobom som vytvoril certifikát pre monitoring server:

10.10.8.5
mon.ibasterisk.local

Privátny kľúč:

openssl genrsa -out docker-10.10.8.5-key.pem 4096

CSR:

openssl req \
  -subj "/CN=10.10.8.5" \
  -sha256 \
  -new \
  -key docker-10.10.8.5-key.pem \
  -out docker-10.10.8.5.csr

SAN konfigurácia:

cat > docker-10.10.8.5-ext.cnf <<'EOF'
subjectAltName = IP:10.10.8.5,DNS:mon.ibasterisk.local
extendedKeyUsage = serverAuth
EOF

A podpis:

openssl x509 \
  -req \
  -days 825 \
  -sha256 \
  -in docker-10.10.8.5.csr \
  -CA docker-ca.pem \
  -CAkey docker-ca-key.pem \
  -CAserial docker-ca.srl \
  -out docker-10.10.8.5-cert.pem \
  -extfile docker-10.10.8.5-ext.cnf

Kontrola SAN:

openssl x509 \
  -in docker-10.10.8.5-cert.pem \
  -noout -text | grep -A2 "Subject Alternative Name"

Výsledok:

X509v3 Subject Alternative Name:
    IP Address:10.10.8.5, DNS:mon.ibasterisk.local

Klientsky certifikát pre Watchtower

Serverové certifikáty máme hotové. Teraz potrebujeme certifikát, ktorým sa bude Watchtower autentifikovať voči Docker daemonu.

Vytvoril som privátny kľúč:

openssl genrsa -out watchtower-key.pem 4096

A CSR:

openssl req \
  -subj "/CN=watchtower-10.10.8.6" \
  -new \
  -sha256 \
  -key watchtower-key.pem \
  -out watchtower.csr

Tentokrát nejde o serverový, ale o klientsky certifikát.

Preto som vytvoril:

cat > watchtower-ext.cnf <<'EOF'
extendedKeyUsage = clientAuth
EOF

Certifikát som podpísal rovnakou Docker CA:

openssl x509 \
  -req \
  -days 825 \
  -sha256 \
  -in watchtower.csr \
  -CA docker-ca.pem \
  -CAkey docker-ca-key.pem \
  -CAserial docker-ca.srl \
  -out watchtower-cert.pem \
  -extfile watchtower-ext.cnf

Privátny kľúč klienta som zabezpečil:

chmod 400 watchtower-key.pem
chmod 444 watchtower-cert.pem

Kontrola:

openssl x509 \
  -in watchtower-cert.pem \
  -noout \
  -subject \
  -issuer \
  -dates \
  -ext extendedKeyUsage

Výsledok:

subject=CN=watchtower-10.10.8.6
issuer=CN=iBasterisk Docker CA

a hlavne:

TLS Web Client Authentication

To potvrdzuje, že certifikát je určený na autentifikáciu klienta.

Čo máme v tejto chvíli pripravené

Na centrálnom serveri máme približne:

/etc/watchtower-pki/
│
├── docker-ca.pem
├── docker-ca-key.pem
├── docker-ca.srl
│
├── docker-10.10.8.4-cert.pem
├── docker-10.10.8.4-key.pem
├── docker-10.10.8.4.csr
│
├── docker-10.10.8.5-cert.pem
├── docker-10.10.8.5-key.pem
├── docker-10.10.8.5.csr
│
├── watchtower-cert.pem
├── watchtower-key.pem
└── watchtower.csr

Z pohľadu bezpečnosti je najdôležitejšie:

docker-ca-key.pem

Tento súbor nesmie opustiť centrálny PKI server.

Na vzdialené Docker hosty pôjdu iba ich vlastné serverové certifikáty, serverové privátne kľúče a verejný certifikát CA.

Na 10.10.8.4 teda neskôr skončí:

ca.pem
server-cert.pem
server-key.pem

a rovnako na 10.10.8.5.

Watchtower na 10.10.8.6 bude používať:

docker-ca.pem
watchtower-cert.pem
watchtower-key.pem

3. Konfigurácia Docker daemonu pre vzdialený prístup cez mTLS

Po vytvorení certifikátov je ďalším krokom sprístupnenie Docker API na vzdialených hostoch.

V mojom prípade ide o:

10.10.8.4
10.10.8.5

Docker bude na oboch serveroch naďalej používať lokálny socket:

/var/run/docker.sock

a zároveň pribudne zabezpečený TCP listener:

10.10.8.4:2376
10.10.8.5:2376

Port 2376 používam výhradne s TLS a overovaním klientského certifikátu.

Architektúra vyzerá takto:

Kontrola existujúcej Docker konfigurácie

Pred akoukoľvek zmenou odporúčam najskôr zistiť, ako je Docker daemon aktuálne spúšťaný:

sudo systemctl cat docker | grep -E '^\[Service\]|^ExecStart'

V mojom prípade bol Docker spúšťaný takto:

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Taktiež som skontroloval:

sudo ss -lntp | grep -E ':(2375|2376)\b'

Pred konfiguráciou nevystupoval žiadny listener:

2375/2376 momentalne nepocuvaju

To je správny východiskový stav.

Prenos serverových certifikátov

Na každý Docker host potrebujeme iba:

CA certificate
server certificate
server private key

Nikdy tam neposielame:

docker-ca-key.pem

Privátny kľúč CA zostáva iba na centrálnom PKI serveri.

Na Docker hoste som vytvoril:

sudo mkdir -p /etc/docker/tls
sudo chmod 700 /etc/docker/tls

Výsledné súbory sú:

/etc/docker/tls/ca.pem
/etc/docker/tls/server-cert.pem
/etc/docker/tls/server-key.pem

Nastavenie práv:

sudo chmod 444 /etc/docker/tls/ca.pem
sudo chmod 444 /etc/docker/tls/server-cert.pem
sudo chmod 400 /etc/docker/tls/server-key.pem

Výsledok:

-r--r--r-- ca.pem
-r--r--r-- server-cert.pem
-r-------- server-key.pem

Overenie certifikátu

Pred reštartom Dockeru som overil, že serverový certifikát je skutočne podpísaný našou CA:

sudo openssl verify \
  -CAfile /etc/docker/tls/ca.pem \
  /etc/docker/tls/server-cert.pem

Výsledok musí byť:

/etc/docker/tls/server-cert.pem: OK

Ďalej som overil, že certifikát a privátny kľúč patria k sebe.

Certifikát:

sudo openssl x509 \
  -in /etc/docker/tls/server-cert.pem \
  -pubkey -noout | sha256sum

Privátny kľúč:

sudo openssl pkey \
  -in /etc/docker/tls/server-key.pem \
  -pubout | sha256sum

Obidva SHA256 hashe musia byť rovnaké.

Napríklad:

25b4724dd654398c4da2b89acf2402f424682ea171c527de363854278acb03f4
25b4724dd654398c4da2b89acf2402f424682ea171c527de363854278acb03f4

Až potom pokračujem konfiguráciou Docker daemonu.

Zapnutie live-restore

Keďže na Docker hostoch bežia produkčné služby, nechcel som, aby krátky reštart samotného Docker daemonu automaticky ukončil všetky bežiace kontajnery.

Preto používam:

"live-restore": true

Na 10.10.8.4, kde pôvodne daemon.json neexistoval, som vytvoril:

sudo nano /etc/docker/daemon.json
{
  "live-restore": true
}

Na 10.10.8.5 som už mal definované DNS servery, takže výsledok vyzeral napríklad takto:

{
  "dns": ["10.10.8.2", "8.8.8.8", "1.1.1.1"],
  "live-restore": true
}

Pred použitím som syntax vždy overil:

sudo dockerd --validate --config-file=/etc/docker/daemon.json

Správny výsledok:

configuration OK

Následne stačí reload:

sudo systemctl reload docker

A kontrola:

sudo docker info | grep -i "Live Restore"

Výsledok:

Live Restore Enabled: true

Systemd override pre Docker API

Keďže Docker už bol spúšťaný cez:

-H fd://

nepridával som parameter hosts do daemon.json.

Namiesto toho som použil systemd override.

Pre host 10.10.8.4:

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/remote-tls.conf >/dev/null <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://10.10.8.4:2376 --tlsverify --tlscacert=/etc/docker/tls/ca.pem --tlscert=/etc/docker/tls/server-cert.pem --tlskey=/etc/docker/tls/server-key.pem --containerd=/run/containerd/containerd.sock
EOF

Pre 10.10.8.5 je konfigurácia rovnaká, mení sa iba IP:

sudo tee /etc/systemd/system/docker.service.d/remote-tls.conf >/dev/null <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://10.10.8.5:2376 --tlsverify --tlscacert=/etc/docker/tls/ca.pem --tlscert=/etc/docker/tls/server-cert.pem --tlskey=/etc/docker/tls/server-key.pem --containerd=/run/containerd/containerd.sock
EOF

Dôležitá je dvojica:

-H fd://
-H tcp://10.10.8.x:2376

Prvá zachováva lokálny Docker socket.

Druhá pridáva vzdialený TLS listener.

Parameter:

--tlsverify

znamená, že Docker nebude iba šifrovať komunikáciu, ale bude zároveň vyžadovať platný klientsky certifikát podpísaný našou CA.

Načítanie systemd konfigurácie

Po vytvorení override:

sudo systemctl daemon-reload

Pred reštartom som si ešte skontroloval výsledný ExecStart:

sudo systemctl show docker -p ExecStart --no-pager

Na 10.10.8.5 napríklad:

/usr/bin/dockerd
-H fd://
-H tcp://10.10.8.5:2376
--tlsverify
--tlscacert=/etc/docker/tls/ca.pem
--tlscert=/etc/docker/tls/server-cert.pem
--tlskey=/etc/docker/tls/server-key.pem
--containerd=/run/containerd/containerd.sock

Ak to sedí, Docker môžeme reštartovať:

sudo systemctl restart docker

Kontrola služby

Po reštarte:

sudo systemctl is-active docker

Výsledok:

active

A kontrola TCP listenera:

sudo ss -lntp | grep 2376
Na prvom hoste:

LISTEN ... 10.10.8.4:2376 ... dockerd

Na druhom hoste:

LISTEN ... 10.10.8.5:2376 ... dockerd

Tým je TLS Docker API aktívne.

Kontrola kontajnerov po reštarte

Po zásahu som si vždy overil existujúce kontajnery:

sudo docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'

Keďže som mal zapnuté:

Live Restore Enabled: true

kontajnery zostali počas reštartu Docker daemonu bežať.

Pri produkčnom hoste je to veľmi užitočné, ale stále odporúčam robiť podobnú zmenu v čase, keď prípadný krátky výpadok nie je kritický.

Test mTLS z Watchtower servera

Teraz môžeme z 10.10.8.6 overiť, či Docker API skutočne vyžaduje klientsky certifikát.

Prejdeme do PKI adresára:

sudo -i
cd /etc/watchtower-pki

Test so správnym klientskym certifikátom

Pre 10.10.8.4:

curl \
  --cacert docker-ca.pem \
  --cert watchtower-cert.pem \
  --key watchtower-key.pem \
  https://10.10.8.4:2376/_ping

Správny výsledok:

OK

Pre druhý host:

curl \
  --cacert docker-ca.pem \
  --cert watchtower-cert.pem \
  --key watchtower-key.pem \
  https://10.10.8.5:2376/_ping

Výsledok:

OK

To znamená, že:

server certificate       OK
CA trust                 OK
client certificate       OK
private key              OK
network connectivity     OK
Docker TLS API           OK

Test bez klientského certifikátu

Veľmi dôležitý je aj opačný test.

curl \
  --cacert docker-ca.pem \
  https://10.10.8.4:2376/_ping

Docker spojenie odmietne:

OpenSSL SSL_read:
tlsv13 alert certificate required

Rovnako na .5:

curl \
  --cacert docker-ca.pem \
  https://10.10.8.5:2376/_ping

opäť:

Odporúčané dodatočné zabezpečenie firewallom

mTLS je hlavná ochranná vrstva, ale v produkčnom prostredí by som port 2376 navyše obmedzil firewallom tak, aby bol dostupný iba z Watchtower servera:

10.10.8.6

Logicky teda:

10.10.8.6 → 10.10.8.4:2376    ALLOW
10.10.8.6 → 10.10.8.5:2376    ALLOW

ostatné zdrojové IP             DENY

V mojom pôvodnom nasadení bol UFW na hostoch vypnutý, takže toto je ďalšia hardening vrstva, ktorú je vhodné doplniť podľa používaného firewallu.

Ak sa používa UFW, princíp môže byť napríklad:

sudo ufw allow from 10.10.8.6 to any port 2376 proto tcp

Samotné zapnutie UFW však netreba robiť naslepo na vzdialenom serveri — pred jeho aktiváciou treba mať povolené aj SSH a všetky ostatné produkčné porty.

Upratanie PKI materiálu

Po úspešnom nasadení odporúčam z Docker hostov odstrániť všetky dočasné CSR súbory a najmä akékoľvek omylom prenesené CA privátne kľúče.

Na vzdialenom Docker hoste majú zostať iba:

/etc/docker/tls/
├── ca.pem
├── server-cert.pem
└── server-key.pem

Privátny kľúč CA:

docker-ca-key.pem

má zostať výhradne na PKI serveri.

Výsledok

Po dokončení tejto kapitoly máme pripravenú zabezpečenú komunikačnú vrstvu:

Docker API je dostupné vzdialene, ale klient bez platného certifikátu sa k nemu nedostane.

V ďalšej kapitole môžeme spraviť 4. Nasadenie centrálneho Watchtoweru na 10.10.8.6 — celé docker-compose.yml pre watchtower-84 a watchtower-85, plánovanie o 03:00/03:30, label-enable, cleanup a vysvetlenie, prečo používame dve Watchtower inštancie.

4. Inštalácia centrálneho Watchtower servera

Watchtower v tomto riešení neinštalujem ako systémový balík. Beží ako klasický Docker kontajner na centrálnom serveri:

10.10.8.6
freeipa.ibasterisk.local

Predpokladom je funkčný Docker a Docker Compose.

Kontrola:

docker version
docker compose version

Ak používateľ nemá prístup k /var/run/docker.sock, príkazy je možné spúšťať cez:

sudo docker ...

V mojom prípade používam udržiavaný Watchtower image:

nickfedor/watchtower:latest

Na serveri som vytvoril dva samostatné projekty:

sudo mkdir -p /opt/watchtower-84
sudo mkdir -p /opt/watchtower-85

Každá inštancia spravuje jeden vzdialený Docker daemon:

watchtower-84 → 10.10.8.4
watchtower-85 → 10.10.8.5

Takto zostáva konfigurácia jednoduchá a každá inštancia môže mať vlastný harmonogram.

Helper skript na vytvorenie Docker CA

Namiesto ručného zadávania všetkých príkazov môžeme v dokumentácii ponúknuť aj skript.

Napríklad:

sudo nano /usr/local/sbin/create-docker-ca.sh

Obsah:

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

PKI_DIR="/etc/watchtower-pki"

mkdir -p "$PKI_DIR"
chmod 700 "$PKI_DIR"

cd "$PKI_DIR"

if [[ -f docker-ca-key.pem || -f docker-ca.pem ]]; then
    echo "ERROR: Docker CA already exists."
    exit 1
fi

echo "Creating Docker CA private key..."

openssl genrsa \
    -out docker-ca-key.pem \
    4096

echo "Creating Docker CA certificate..."

openssl req \
    -new \
    -x509 \
    -days 3650 \
    -key docker-ca-key.pem \
    -sha256 \
    -out docker-ca.pem \
    -subj "/CN=iBasterisk Docker CA"

chmod 400 docker-ca-key.pem
chmod 444 docker-ca.pem

echo
echo "Docker CA created:"
echo "  $PKI_DIR/docker-ca.pem"
echo "  $PKI_DIR/docker-ca-key.pem"

Nastavenie práv:

sudo chmod 700 /usr/local/sbin/create-docker-ca.sh

Spustenie:

sudo /usr/local/sbin/create-docker-ca.sh

Výhodou je, že skript skončí chybou, ak CA už existuje. Nemôže teda nepozornosťou prepísať existujúcu certifikačnú autoritu.

Skript na vytvorenie serverového Docker certifikátu

Ďalší helper môže generovať certifikát pre ľubovoľný Docker host.

sudo nano /usr/local/sbin/create-docker-server-cert.sh

Obsah:

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

PKI_DIR="/etc/watchtower-pki"

if [[ $# -ne 2 ]]; then
    echo "Usage:"
    echo "  $0 <IP_ADDRESS> <DNS_NAME>"
    echo
    echo "Example:"
    echo "  $0 10.10.8.5 mon.ibasterisk.local"
    exit 1
fi

IP="$1"
DNS="$2"

cd "$PKI_DIR"

CA_CERT="docker-ca.pem"
CA_KEY="docker-ca-key.pem"

KEY="docker-${IP}-key.pem"
CSR="docker-${IP}.csr"
CERT="docker-${IP}-cert.pem"
EXT="docker-${IP}-ext.cnf"

if [[ ! -f "$CA_CERT" || ! -f "$CA_KEY" ]]; then
    echo "ERROR: Docker CA not found."
    exit 1
fi

if [[ -f "$KEY" || -f "$CERT" ]]; then
    echo "ERROR: Certificate for $IP already exists."
    exit 1
fi

echo "Creating private key for $IP..."

openssl genrsa \
    -out "$KEY" \
    4096

echo "Creating CSR..."

openssl req \
    -subj "/CN=${IP}" \
    -sha256 \
    -new \
    -key "$KEY" \
    -out "$CSR"

cat > "$EXT" <<EOF
subjectAltName = IP:${IP},DNS:${DNS}
extendedKeyUsage = serverAuth
EOF

echo "Signing certificate..."

openssl x509 \
    -req \
    -days 825 \
    -sha256 \
    -in "$CSR" \
    -CA "$CA_CERT" \
    -CAkey "$CA_KEY" \
    -CAserial docker-ca.srl \
    -CAcreateserial \
    -out "$CERT" \
    -extfile "$EXT"

chmod 400 "$KEY"
chmod 444 "$CERT"

echo
echo "Certificate created:"
echo "  $CERT"
echo "  $KEY"
echo
echo "Certificate details:"
openssl x509 \
    -in "$CERT" \
    -noout \
    -subject \
    -issuer \
    -dates

openssl x509 \
    -in "$CERT" \
    -noout -text |
    grep -A2 "Subject Alternative Name"

Práva:

sudo chmod 700 /usr/local/sbin/create-docker-server-cert.sh

Pre prvý host:

sudo /usr/local/sbin/create-docker-server-cert.sh \
  10.10.8.4 \
  mail-ibasterisk

Pre druhý:

sudo /usr/local/sbin/create-docker-server-cert.sh \
  10.10.8.5 \
  mon.ibasterisk.local

Takto sa veľmi pekne zjednoduší celá PKI časť dokumentácie.

Skript na vytvorenie Watchtower klientského certifikátu

Rovnako môžeme automatizovať aj klientsky certifikát.

sudo nano /usr/local/sbin/create-watchtower-client-cert.sh

Obsah:

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

PKI_DIR="/etc/watchtower-pki"

cd "$PKI_DIR"

if [[ ! -f docker-ca.pem || ! -f docker-ca-key.pem ]]; then
    echo "ERROR: Docker CA not found."
    exit 1
fi

if [[ -f watchtower-key.pem || -f watchtower-cert.pem ]]; then
    echo "ERROR: Watchtower certificate already exists."
    exit 1
fi

openssl genrsa \
    -out watchtower-key.pem \
    4096

openssl req \
    -subj "/CN=watchtower-10.10.8.6" \
    -new \
    -sha256 \
    -key watchtower-key.pem \
    -out watchtower.csr

cat > watchtower-ext.cnf <<'EOF'
extendedKeyUsage = clientAuth
EOF

openssl x509 \
    -req \
    -days 825 \
    -sha256 \
    -in watchtower.csr \
    -CA docker-ca.pem \
    -CAkey docker-ca-key.pem \
    -CAserial docker-ca.srl \
    -out watchtower-cert.pem \
    -extfile watchtower-ext.cnf

chmod 400 watchtower-key.pem
chmod 444 watchtower-cert.pem

echo
echo "Watchtower client certificate created."
echo

openssl x509 \
    -in watchtower-cert.pem \
    -noout \
    -subject \
    -issuer \
    -dates \
    -ext extendedKeyUsage

Spustenie:

sudo chmod 700 /usr/local/sbin/create-watchtower-client-cert.sh
sudo /usr/local/sbin/create-watchtower-client-cert.sh

Na konci chceme:

TLS Web Client Authentication

Bezpečné vytvorenie SMTP secretu

Určite by som do článku dal aj helper, ktorý sme používali na SMTP.

Výhoda je, že App Password nemusíme zadávať priamo do shell príkazu a tým pádom sa neobjaví v shell histórii.

Najprv:

sudo mkdir -p /etc/watchtower-notify
sudo chmod 700 /etc/watchtower-notify

Helper:

sudo nano /tmp/create-watchtower-smtp.py

Obsah:

import os
import getpass
from urllib.parse import quote, urlencode

smtp_host = input("SMTP hostname: ").strip()
mail_to = input("Notification recipient: ").strip()
password = getpass.getpass(
    "App Password for updater@ibasterisk.eu: "
)

username = "updater@ibasterisk.eu"

query = urlencode({
    "fromaddress": username,
    "toaddresses": mail_to,
    "encryption": "ExplicitTLS",
    "usestarttls": "yes",
    "auth": "Plain",
    "timeout": "30s",
})

url = (
    "smtp://"
    + quote(username, safe="")
    + ":"
    + quote(password, safe="")
    + "@"
    + smtp_host
    + ":587/?"
    + query
)

path = "/etc/watchtower-notify/notification-url.txt"

with open(path, "w") as f:
    f.write(url + "\n")

os.chmod(path, 0o600)

print("SMTP secret created:", path)

Spustenie:

sudo python3 /tmp/create-watchtower-smtp.py

Program sa opýta:

SMTP hostname:
Notification recipient:
App Password for updater@ibasterisk.eu:

Pri zadávaní hesla sa nič nezobrazuje.

Po vytvorení:

sudo rm -f /tmp/create-watchtower-smtp.py

Kontrola:

sudo ls -l /etc/watchtower-notify/notification-url.txt

Výsledok:

-rw------- 1 root root ... notification-url.txt

Dôležité:

cat /etc/watchtower-notify/notification-url.txt

nepoužívame, pretože URL obsahuje SMTP App Password.

Inštalácia samotného Watchtoweru

Po pripravení PKI nemusíme inštalovať žiadny ďalší balík.

Vytvoríme Compose projekt:

sudo mkdir -p /opt/watchtower-84

A napríklad:

sudo nano /opt/watchtower-84/docker-compose.yml

Minimálna verzia ešte bez mailov môže vyzerať:

services:
  watchtower-84:
    image: nickfedor/watchtower:latest
    container_name: watchtower-84
    restart: unless-stopped

    environment:
      TZ: Europe/Bratislava

      DOCKER_HOST: tcp://10.10.8.4:2376
      DOCKER_TLS_VERIFY: "1"
      DOCKER_CERT_PATH: /certs

      WATCHTOWER_LABEL_ENABLE: "true"
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_SCHEDULE: "0 0 3 * * *"

    volumes:
      - /etc/watchtower-pki/docker-ca.pem:/certs/ca.pem:ro
      - /etc/watchtower-pki/watchtower-cert.pem:/certs/cert.pem:ro
      - /etc/watchtower-pki/watchtower-key.pem:/certs/key.pem:ro

Kontrola:

cd /opt/watchtower-84
sudo docker compose config

Stiahnutie image:

sudo docker compose pull

Spustenie:

sudo docker compose up -d

Kontrola:

sudo docker ps --filter name=watchtower-84

A log:

sudo docker logs watchtower-84 --tail 50

Pri úspešnom pripojení sme napríklad videli:

Watchtower 1.22.1 using Docker API v1.55
Next scheduled run: 2026-09-15 03:00:00 CEST

Pre druhý Docker host vytvoríme samostatne:

/opt/watchtower-85/

s:

DOCKER_HOST: tcp://10.10.8.5:2376
WATCHTOWER_SCHEDULE: "0 30 3 * * *"

Teda:

03:00 → Docker 10.10.8.4
03:30 → Docker 10.10.8.5

5. Finálna konfigurácia Watchtoweru s e-mailovými notifikáciami

Po overení komunikácie cez mTLS a základnom spustení Watchtoweru môžeme prejsť na finálnu konfiguráciu, ktorú používam v produkcii.

Na centrálnom serveri 10.10.8.6 bežia dve samostatné Watchtower inštancie:

watchtower-84 → Docker host 10.10.8.4
watchtower-85 → Docker host 10.10.8.5

Každá inštancia má vlastný harmonogram, vlastné označenie v notifikáciách a pripája sa iba k jednému vzdialenému Docker daemonu.

Aktualizácie som rozdelil časovo:

03:00 → 10.10.8.4
03:30 → 10.10.8.5

Tým sa oba servery nekontrolujú a prípadne neaktualizujú naraz.

5.1 Šablóna e-mailových notifikácií

Najskôr som vytvoril spoločnú šablónu, ktorú používajú obe Watchtower inštancie:

sudo nano /etc/watchtower-notify/update-template.txt

Obsah:

{{- if .Report -}}
{{- with .Report -}}
{{- if or .Updated .Failed -}}
Watchtower - {{.Host}}

Scanned: {{len .Scanned}}
Updated: {{len .Updated}}
Failed: {{len .Failed}}

{{- range .Updated}}

UPDATED: {{.Name}}
Image: {{.ImageName}}
{{- end}}

{{- range .Failed}}

FAILED: {{.Name}}
Image: {{.ImageName}}
Error: {{.Error}}
{{- end}}
{{- end -}}
{{- end -}}
{{- end -}}

Následne som nastavil práva:

sudo chmod 444 /etc/watchtower-notify/update-template.txt

Táto šablóna je zámerne navrhnutá tak, aby vytvorila obsah správy iba v prípade, že:

kontajner bol aktualizovaný
alebo
aktualizácia skončila chybou

Ak Watchtower iba skontroluje image a nič sa nezmenilo, šablóna nevytvorí obsah správy a zbytočný e-mail sa neodošle.

Výsledný adresár s notifikačnými súbormi teda obsahuje:

/etc/watchtower-notify/
├── notification-url.txt
└── update-template.txt

SMTP URL obsahujúce App Password zostáva:

-rw------- root root notification-url.txt

zatiaľ čo samotná šablóna môže byť iba na čítanie:

-r--r--r-- root root update-template.txt

5.2 Finálna konfigurácia watchtower-84

Prvá inštancia spravuje Docker host:

10.10.8.4

Konfigurácia sa nachádza v:

/opt/watchtower-84/docker-compose.yml

Súbor som vytvoril:

sudo nano /opt/watchtower-84/docker-compose.yml

Finálna konfigurácia:

services:
  watchtower-84:
    image: nickfedor/watchtower:latest
    container_name: watchtower-84
    restart: unless-stopped

    environment:
      TZ: Europe/Bratislava

      DOCKER_HOST: tcp://10.10.8.4:2376
      DOCKER_TLS_VERIFY: "1"
      DOCKER_CERT_PATH: /certs

      WATCHTOWER_LABEL_ENABLE: "true"
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_SCHEDULE: "0 0 3 * * *"

      WATCHTOWER_NOTIFICATION_URL: /notify/notification-url.txt
      WATCHTOWER_NOTIFICATION_REPORT: "true"
      WATCHTOWER_NOTIFICATION_TEMPLATE_FILE: /notify/update-template.txt
      WATCHTOWER_NO_STARTUP_MESSAGE: "true"
      WATCHTOWER_NOTIFICATIONS_HOSTNAME: "docker-10.10.8.4"

    volumes:
      - /etc/watchtower-pki/docker-ca.pem:/certs/ca.pem:ro
      - /etc/watchtower-pki/watchtower-cert.pem:/certs/cert.pem:ro
      - /etc/watchtower-pki/watchtower-key.pem:/certs/key.pem:ro

      - /etc/watchtower-notify/notification-url.txt:/notify/notification-url.txt:ro
      - /etc/watchtower-notify/update-template.txt:/notify/update-template.txt:ro

Pred spustením som konfiguráciu overil:

cd /opt/watchtower-84
sudo docker compose config

Ak Compose nehlási chybu, image môžeme stiahnuť:

sudo docker compose pull

a následne spustiť:

sudo docker compose up -d

Kontrola:

sudo docker ps --filter name=watchtower-84

Log:

sudo docker logs watchtower-84 --tail 50

Pri správnej konfigurácii Watchtower oznámi, že sa pripojil k vzdialenému Docker API a vypočíta čas ďalšej kontroly.

5.3 Finálna konfigurácia watchtower-85

Druhá inštancia spravuje:

10.10.8.5

Compose súbor sa nachádza v:

/opt/watchtower-85/docker-compose.yml

Vytvorenie:

sudo nano /opt/watchtower-85/docker-compose.yml

Obsah:

services:
  watchtower-85:
    image: nickfedor/watchtower:latest
    container_name: watchtower-85
    restart: unless-stopped

    environment:
      TZ: Europe/Bratislava

      DOCKER_HOST: tcp://10.10.8.5:2376
      DOCKER_TLS_VERIFY: "1"
      DOCKER_CERT_PATH: /certs

      WATCHTOWER_LABEL_ENABLE: "true"
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_SCHEDULE: "0 30 3 * * *"

      WATCHTOWER_NOTIFICATION_URL: /notify/notification-url.txt
      WATCHTOWER_NOTIFICATION_REPORT: "true"
      WATCHTOWER_NOTIFICATION_TEMPLATE_FILE: /notify/update-template.txt
      WATCHTOWER_NO_STARTUP_MESSAGE: "true"
      WATCHTOWER_NOTIFICATIONS_HOSTNAME: "docker-10.10.8.5"

    volumes:
      - /etc/watchtower-pki/docker-ca.pem:/certs/ca.pem:ro
      - /etc/watchtower-pki/watchtower-cert.pem:/certs/cert.pem:ro
      - /etc/watchtower-pki/watchtower-key.pem:/certs/key.pem:ro

      - /etc/watchtower-notify/notification-url.txt:/notify/notification-url.txt:ro
      - /etc/watchtower-notify/update-template.txt:/notify/update-template.txt:ro

Kontrola konfigurácie:

cd /opt/watchtower-85
sudo docker compose config

Stiahnutie image:

sudo docker compose pull

Spustenie:

sudo docker compose up -d

Kontrola:

sudo docker ps --filter name=watchtower-85

A log:

sudo docker logs watchtower-85 --tail 50

5.4 Čo znamenajú jednotlivé parametre

Najdôležitejšia časť konfigurácie je:

DOCKER_HOST: tcp://10.10.8.4:2376
DOCKER_TLS_VERIFY: "1"
DOCKER_CERT_PATH: /certs

DOCKER_HOST určuje vzdialený Docker daemon.

DOCKER_TLS_VERIFY zapína overovanie TLS certifikátov a DOCKER_CERT_PATH určuje adresár, kde Watchtower nájde:

ca.pem
cert.pem
key.pem

Tieto názvy vzniknú pomocou bind mountov:

- /etc/watchtower-pki/docker-ca.pem:/certs/ca.pem:ro
- /etc/watchtower-pki/watchtower-cert.pem:/certs/cert.pem:ro
- /etc/watchtower-pki/watchtower-key.pem:/certs/key.pem:ro

Watchtower teda privátny kľúč nekopíruje do kontajnera natrvalo. Súbor je do kontajnera pripojený iba na čítanie.

Parameter:

WATCHTOWER_LABEL_ENABLE: "true"

zapína label-only režim.

To znamená, že Watchtower nebude aktualizovať všetky kontajnery na vzdialenom serveri. Spracuje iba tie, ktoré majú:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

Parameter:

WATCHTOWER_CLEANUP: "true"

spôsobí, že po úspešnej aktualizácii Watchtower odstráni starý image, ktorý už nie je potrebný.

Bez cleanupu by sa na Docker hostoch postupne hromadili staré image.

5.5 Harmonogram aktualizácií

Watchtower používa pri WATCHTOWER_SCHEDULE cron výraz so sekundami.

Prvá inštancia má:

WATCHTOWER_SCHEDULE: "0 0 3 * * *"

čo znamená:

sekunda:   0
minúta:    0
hodina:    3
deň:       každý
mesiac:    každý
deň týždňa: každý

Teda každý deň o:

03:00

Druhá inštancia používa:

WATCHTOWER_SCHEDULE: "0 30 3 * * *"

Čiže:

03:30

Časové pásmo zabezpečuje:

TZ: Europe/Bratislava

Takto sa harmonogram riadi lokálnym časom vrátane prechodu medzi letným a zimným časom.


5.6 Nastavenie notifikácií

Watchtower dostáva SMTP konfiguráciu zo súboru:

WATCHTOWER_NOTIFICATION_URL: /notify/notification-url.txt

Súbor je do kontajnera pripojený iba na čítanie:

- /etc/watchtower-notify/notification-url.txt:/notify/notification-url.txt:ro

Vďaka tomu sa SMTP App Password nenachádza priamo v:

docker-compose.yml

Reportovací režim zapína:

WATCHTOWER_NOTIFICATION_REPORT: "true"

a vlastnú šablónu určuje:

WATCHTOWER_NOTIFICATION_TEMPLATE_FILE: /notify/update-template.txt

Parameter:

WATCHTOWER_NO_STARTUP_MESSAGE: "true"

zabraňuje tomu, aby Watchtower posielal zbytočnú notifikáciu pri každom svojom spustení.

Nakoniec používam:

WATCHTOWER_NOTIFICATIONS_HOSTNAME: "docker-10.10.8.4"

alebo:

WATCHTOWER_NOTIFICATIONS_HOSTNAME: "docker-10.10.8.5"

V e-maile tak okamžite vidím, ktorého Docker hosta sa správa týka.

Napríklad:

Watchtower - docker-10.10.8.4

Scanned: 3
Updated: 1
Failed: 0

UPDATED: element
Image: vectorim/element-web:latest

Pri chybe môže report vyzerať napríklad:

Watchtower - docker-10.10.8.4

Scanned: 3
Updated: 0
Failed: 1

FAILED: changedetection
Image: dgtlmoon/changedetection.io
Error: ...

5.7 Kontrola pripojených súborov

Po spustení je vhodné overiť, že všetky bind mounty sú naozaj dostupné.

Použil som:

sudo docker inspect watchtower-84 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

A podobne:

sudo docker inspect watchtower-85 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

Výstup by mal obsahovať približne:

/etc/watchtower-pki/docker-ca.pem -> /certs/ca.pem
/etc/watchtower-pki/watchtower-cert.pem -> /certs/cert.pem
/etc/watchtower-pki/watchtower-key.pem -> /certs/key.pem
/etc/watchtower-notify/notification-url.txt -> /notify/notification-url.txt
/etc/watchtower-notify/update-template.txt -> /notify/update-template.txt

Watchtower image neobsahuje klasický shell, takže príkazy typu:

docker exec watchtower-84 sh

nemusia fungovať.

Na kontrolu konfigurácie je preto vhodnejšie používať:

docker inspect

docker inspect

sudo docker ps --filter name=watchtower

Očakávaný stav:

watchtower-84    Up ...
watchtower-85    Up ...

Logy:

sudo docker logs watchtower-84 --tail 30
sudo docker logs watchtower-85 --tail 30

V mojom nasadení sa Watchtower úspešne pripájal cez mTLS k obom vzdialeným Docker hostom a čakal na naplánované spustenie:

watchtower-84 → každý deň 03:00
watchtower-85 → každý deň 03:30

Tým máme centrálny Watchtower nakonfigurovaný. Stále však nebude automaticky aktualizovať žiadny kontajner, pokiaľ mu to explicitne nepovolíme pomocou Docker labelu.

6. Výber kontajnerov pomocou Docker labelov

Watchtower je už pripojený k vzdialeným Docker hostom, ale v konfigurácii používam:

WATCHTOWER_LABEL_ENABLE: "true"

To znamená, že automatická aktualizácia nie je povolená globálne pre všetky kontajnery.

Každý kontajner, ktorý má Watchtower spravovať, musí mať explicitne nastavený label:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

Kontajner bez tohto labelu Watchtower pri aktualizácii ignoruje.

Týmto spôsobom môžem na rovnakom Docker hoste prevádzkovať napríklad desať kontajnerov, ale automatické aktualizácie povoliť iba dvom alebo trom.

6.1 Prečo používam opt-in model

Pri automatických aktualizáciách preferujem princíp:

defaultne zakázané
explicitne povolené

Namiesto toho, aby Watchtower aktualizoval všetko a následne som vytváral výnimky, automatickú aktualizáciu povoľujem jednotlivo.

Výsledok môže vyzerať napríklad takto:

10.10.8.4

Element                AUTO
ChangeDetection        AUTO
Browserless Chrome     AUTO
Synapse                MANUAL
Mailcow                MANUAL
ostatné kontajnery     MANUAL

Na druhom serveri:

10.10.8.5

Grafana                AUTO
Zabbix                 MANUAL
MariaDB                MANUAL
PostgreSQL             MANUAL
Passbolt               MANUAL
NetBox                 MANUAL
FreePBX                MANUAL

Takýto model výrazne znižuje riziko, že sa kritická aplikácia alebo databáza aktualizuje bez predchádzajúcej kontroly.

6.2 Povolenie automatickej aktualizácie pre Element

Na Docker hoste:

10.10.8.4

mám aplikáciu Element.

Do príslušnej služby v docker-compose.yaml som pridal:

services:

  element:
    image: vectorim/element-web:latest

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Nie je potrebné meniť ostatnú konfiguráciu služby. Dôležité je iba doplnenie sekcie:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

Po úprave Compose súboru je potrebné konfiguráciu aplikovať.

V mojom prípade:

cd /home/ivan/docker/chat
sudo docker compose config

Ak je konfigurácia v poriadku:

sudo docker compose up -d element

Keďže sa zmenila konfigurácia kontajnera, Docker ho môže znovu vytvoriť.

Následne som overil label:

sudo docker inspect element \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Správny výsledok:

true

Od tejto chvíle je Element zaradený medzi kontajnery, ktoré môže watchtower-84 automaticky aktualizovať.

Synapse bežiaci v rovnakom prostredí som naopak ponechal bez Watchtower labelu.

6.3 ChangeDetection

Rovnaký postup som použil pri ChangeDetection.

Do služby:

services:

  changedetection:
    image: dgtlmoon/changedetection.io

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Po úprave konfigurácie:

cd /home/ivan/docker/changedetection

sudo docker compose config
sudo docker compose up -d changedetection

Kontrola:

sudo docker inspect changedetection \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Výsledok:

true

Watchtower teda môže kontrolovať, či existuje novšia verzia image:

dgtlmoon/changedetection.io

a v prípade potreby kontajner aktualizovať.

6.4 Browserless Chrome

ChangeDetection v mojom prostredí používa aj Browserless Chrome.

Aj tento kontajner som povolil pre automatickú aktualizáciu:

services:

  browserless-chrome:
    image: browserless/chrome

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Po úprave:

sudo docker compose up -d browserless-chrome

Kontrola:

sudo docker inspect browserless-chrome \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Očakávaný výsledok:

true

Na Docker hoste 10.10.8.4 tak Watchtower aktuálne sleduje:

element
changedetection
browserless-chrome

6.5 Grafana na druhom Docker hoste

Na serveri:

10.10.8.5

som pre automatické aktualizácie vybral Grafanu.

Do Compose konfigurácie som pridal:

services:

  grafana:
    image: grafana/grafana:latest

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Následne:

cd ~/grafana

sudo docker-compose \
  -f docker-compose-grafana.yml \
  config

Na tomto serveri používam samostatný príkaz docker-compose, preto aj aplikovanie konfigurácie vyzerá:

sudo docker-compose \
  -f docker-compose-grafana.yml \
  up -d

Kontrola labelu:

sudo docker inspect grafana \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Výsledok:

true

Grafanu následne spravuje:

watchtower-85

na centrálnom serveri 10.10.8.6.

6.6 Kontrola všetkých Watchtower labelov na hoste

Namiesto kontroly každého kontajnera samostatne môžeme vypísať všetky bežiace kontajnery spolu s hodnotou Watchtower labelu:

sudo docker ps -q | xargs -r sudo docker inspect \
  --format '{{.Name}} -> {{index .Config.Labels "com.centurylinklabs.watchtower.enable"}}'

Na 10.10.8.4 môže výsledok vyzerať približne:

/element -> true
/changedetection -> true
/browserless-chrome -> true
/synapse -> <no value>
...

Kontajnery s:

true

sú povolené pre automatické aktualizácie.

Kontajnery bez hodnoty zostávajú mimo automatickej správy Watchtoweru.

Podobne na 10.10.8.5:

/grafana -> true
/zabbix-server -> <no value>
/mariadb -> <no value>
...

6.7 Label nie je jednorazové nastavenie kontajnera

Dôležité je pridávať label priamo do:

docker-compose.yml

alebo:

docker-compose.yaml

Nie iba manuálne do momentálne bežiaceho kontajnera.

Compose súbor predstavuje požadovanú konfiguráciu aplikácie. Ak by sme label pridali iba nejakým jednorazovým príkazom a kontajner neskôr znovu vytvorili z Compose konfigurácie, nastavenie by sa stratilo.

Preto má byť napríklad:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

súčasťou trvalej definície služby.

6.8 Čo sa deje počas automatickej aktualizácie

Ak Watchtower pri naplánovanej kontrole zistí novší image pre kontajner označený správnym labelom, typický postup je:

1. skontroluje aktuálne používaný image
2. overí dostupnosť novšej verzie
3. stiahne nový image
4. zastaví pôvodný kontajner
5. vytvorí nový kontajner s rovnakou konfiguráciou
6. spustí nový kontajner
7. pri zapnutom cleanup odstráni starý image
8. odošle report

Dáta uložené vo volume alebo bind mounte týmto postupom zostávajú zachované.

Preto je pri výbere kontajnerov na automatickú aktualizáciu dôležité, aby aplikácia mala svoje persistentné dáta uložené mimo zapisovateľnej vrstvy samotného kontajnera.

6.9 Výsledný stav

Po pridaní labelov vyzerá moja konfigurácia nasledovne:

Tým máme definované, ktoré kontajnery sa smú aktualizovať automaticky a ktoré zostávajú pod manuálnou správou.

7. Testovanie Watchtoweru a overenie reálnej aktualizácie

Po pridaní labelov je vhodné nečakať na nočný harmonogram, ale celé riešenie otestovať manuálne.

Na tento účel môžeme použiť:

/watchtower --run-once

Watchtower vykoná jednu kontrolu, prípadne aktualizáciu, a následne skončí.

7.1 Manuálny test watchtower-84

Na centrálnom serveri:

10.10.8.6

som spustil:

sudo docker exec watchtower-84 /watchtower --run-once

Watchtower sa cez mTLS pripojí k:

10.10.8.4:2376

a skontroluje iba kontajnery označené:

com.centurylinklabs.watchtower.enable=true

V mojom prípade:

Element
ChangeDetection
Browserless Chrome

Ak existuje novší image, Watchtower ho stiahne a kontajner znovu vytvorí.

Pri teste s Elementom bola aktualizácia úspešná.

Log obsahoval informácie v štýle:

Found new image
Stopping /element
Creating /element
Removing image
Session done

a výsledok:

failed=0
scanned=1
updated=1

Po aktualizácii som skontroloval stav:

sudo docker ps --filter name=element

a následne aj samotnú aplikáciu cez webové rozhranie.

Element fungoval korektne aj po automatickej aktualizácii.

7.2 Manuálny test watchtower-85

Rovnaký test som vykonal aj pre druhú inštanciu:

sudo docker exec watchtower-85 /watchtower --run-once

Táto inštancia sa pripája k:

10.10.8.5:2376

a v mojom prípade sleduje Grafanu.

Počas testu Watchtower našiel novšiu verziu image:

grafana/grafana:latest

starý kontajner zastavil, vytvoril nový a odstránil pôvodný image.

Výsledok bol:

failed=0
scanned=1
updated=1

Po aktualizácii:

sudo docker ps --filter name=grafana

a následne som overil Grafanu cez webové rozhranie.

Aj v tomto prípade prebehla automatická aktualizácia úspešne.

7.3 Overenie aktuálne používaného image

Po aktualizácii je vhodné overiť, aký image kontajner skutočne používa.

Napríklad:

sudo docker inspect element \
  --format '{{.Image}}'

alebo:

sudo docker inspect grafana \
  --format '{{.Image}}'

ID image môžeme porovnať s image dostupným lokálne:

sudo docker image inspect grafana/grafana:latest \
  --format '{{.Id}}'

Ak sa hodnoty zhodujú, kontajner používa aktuálne stiahnutý image.

7.4 Test SMTP notifikácie bez aktualizácie kontajnera

E-mailové notifikácie je dobré otestovať samostatne bez toho, aby sme kvôli testu reálne aktualizovali aplikáciu.

Na to môžeme použiť:

--monitor-only

Pre Grafanu som použil:

sudo docker exec \
  -e WATCHTOWER_NOTIFICATION_TEMPLATE_FILE= \
  watchtower-85 \
  /watchtower \
  --run-once \
  --monitor-only \
  --notification-template 'Watchtower SMTP TEST - docker 10.10.8.5' \
  grafana

Parameter:

--monitor-only

znamená, že Watchtower môže skontrolovať dostupnosť image, ale kontajner nebude zastavovať ani znovu vytvárať.

V logu som dostal:

Shoutrrr: Mail successfully sent to "updater@ibasterisk.eu"!

a testovací e-mail následne dorazil do mailboxu.

Rovnaký test môžeme spraviť pre prvý Docker host:

sudo docker exec \
  -e WATCHTOWER_NOTIFICATION_TEMPLATE_FILE= \
  watchtower-84 \
  /watchtower \
  --run-once \
  --monitor-only \
  --notification-template 'Watchtower SMTP TEST - docker 10.10.8.4' \
  element

Takto vieme samostatne overiť:

SMTP spojenie
STARTTLS
SMTP autentifikáciu
App Password
doručenie správy
Watchtower notification backend

bez zásahu do produkčného kontajnera.

7.5 Overenie notifikačnej konfigurácie

Nastavené premenné môžeme overiť pomocou:

sudo docker inspect watchtower-84 \
  --format '{{range .Config.Env}}{{println .}}{{end}}' |
  grep -E '^WATCHTOWER_(NOTIFICATION_URL|NOTIFICATION_REPORT|NOTIFICATION_TEMPLATE_FILE|NO_STARTUP_MESSAGE|NOTIFICATIONS_HOSTNAME)='

Rovnako:

sudo docker inspect watchtower-85 \
  --format '{{range .Config.Env}}{{println .}}{{end}}' |
  grep -E '^WATCHTOWER_(NOTIFICATION_URL|NOTIFICATION_REPORT|NOTIFICATION_TEMPLATE_FILE|NO_STARTUP_MESSAGE|NOTIFICATIONS_HOSTNAME)='

Výstup by mal obsahovať napríklad:

WATCHTOWER_NOTIFICATION_URL=/notify/notification-url.txt
WATCHTOWER_NOTIFICATION_REPORT=true
WATCHTOWER_NOTIFICATION_TEMPLATE_FILE=/notify/update-template.txt
WATCHTOWER_NO_STARTUP_MESSAGE=true
WATCHTOWER_NOTIFICATIONS_HOSTNAME=docker-10.10.8.4

alebo pre druhú inštanciu:

WATCHTOWER_NOTIFICATIONS_HOSTNAME=docker-10.10.8.5

7.6 Test správy pri reálnej aktualizácii

Pri reálnej aktualizácii už používame štandardnú šablónu.

E-mail môže vyzerať napríklad:

Watchtower - docker-10.10.8.4

Scanned: 3
Updated: 1
Failed: 0

UPDATED: element
Image: vectorim/element-web:latest

Pri chybe:

Watchtower - docker-10.10.8.4

Scanned: 3
Updated: 0
Failed: 1

FAILED: changedetection
Image: dgtlmoon/changedetection.io
Error: ...

Takto viem bez prihlasovania na server okamžite zistiť:

ktorý Docker host vykonal kontrolu
koľko kontajnerov bolo skontrolovaných
ktoré kontajnery boli aktualizované
či aktualizácia skončila chybou

7.7 Pozor na prerušenie --run-once

Počas testovania som narazil aj na jednu praktickú situáciu.

Príkaz:

sudo docker exec watchtower-84 /watchtower --run-once

môže počas sťahovania väčšieho image určitý čas neprodukovovať žiadny nový výstup.

To neznamená, že proces stojí.

Najmä image ako:

browserless/chrome

môže byť väčší a jeho sťahovanie chvíľu trvá.

Preto nie je dobré test prerušiť pomocou:

Ctrl+C

a následne okamžite spustiť druhý --run-once.

Pri mojom teste som presne toto urobil a následný Watchtower proces narazil na:

removal of container ... is already in progress

Dôvodom nebola chyba aplikácie, ale to, že pôvodný Watchtower proces už začal kontajner aktualizovať a druhý proces sa pokúsil pracovať s rovnakým kontajnerom.

7.8 Ako overiť stav po prerušenej aktualizácii

Pred ďalším zásahom som najskôr skontroloval kontajnery:

sudo docker ps -a

Následne konkrétny kontajner:

sudo docker inspect changedetection \
  --format 'Status={{.State.Status}} Image={{.Image}}'

A aktuálny image:

sudo docker image inspect \
  dgtlmoon/changedetection.io:latest \
  --format '{{.Id}}'

Ak ID kontajnera zodpovedá aktuálnemu image a kontajner má stav:

running

aktualizácia mohla v skutočnosti prebehnúť úspešne aj napriek tomu, že druhý Watchtower proces nahlásil chybu.

V mojom prípade ChangeDetection už používal nový image a aplikácia normálne fungovala.

Preto pri podobnom stave neodporúčam kontajner okamžite mazať alebo znova vytvárať.

Najskôr treba overiť jeho reálny stav.

7.9 Kontrola aplikácie po aktualizácii

Úspešný Watchtower log ešte automaticky neznamená, že aplikácia funguje správne.

Po každom prvom automatickom update konkrétnej služby preto odporúčam skontrolovať:

stav kontajnera
aplikačné logy
webové rozhranie
persistentné dáta
závislosti na ostatných službách

Kontrola logov napríklad:

sudo docker logs element --tail 50

alebo:

sudo docker logs grafana --tail 50

Prípadne:

sudo docker logs changedetection --tail 50

Aplikáciu následne overím rovnakým spôsobom ako používateľ.

Až keď toto prebehne bez problémov, nechávam kontajner zaradený do automatických aktualizácií.

7.10 Výsledok testovania

Po dokončení testov mám overené všetky hlavné časti riešenia:

mTLS komunikácia                         OK
Docker API                               OK
Watchtower remote connection             OK
label-only režim                         OK
automatická aktualizácia                 OK
cleanup starých image                    OK
SMTP cez STARTTLS                        OK
App Password                             OK
e-mail pri aktualizácii                  OK
e-mail pri chybe                         OK
bez e-mailu pri bežnej kontrole          OK

Tým je základné nasadenie hotové.

Watchtower teraz každý deň automaticky vykoná:

03:00 → kontrola 10.10.8.4
03:30 → kontrola 10.10.8.5

8. Troubleshooting a najčastejšie problémy

Pri nasadzovaní riešenia sa môže problém objaviť na viacerých miestach — od Docker daemonu, cez TLS certifikáty až po samotný Watchtower alebo SMTP notifikácie.

V tejto kapitole sú najčastejšie problémy, na ktoré som pri nasadení narazil, spolu s postupom kontroly.

8.1 Docker API na porte 2376 nepočúva

Ako prvé je vhodné overiť, či Docker daemon vôbec počúva na zabezpečenom TCP porte:

sudo ss -lntp | grep 2376

Správny výsledok by mal obsahovať napríklad:

LISTEN ... 10.10.8.4:2376 ... dockerd

alebo:

LISTEN ... 10.10.8.5:2376 ... dockerd

Ak sa nič nezobrazí, skontrolujem stav Docker služby:

sudo systemctl status docker --no-pager

a následne výsledný ExecStart:

sudo systemctl show docker -p ExecStart --no-pager

Mal by obsahovať:

-H fd://
-H tcp://10.10.8.x:2376
--tlsverify

Ak som menil systemd override, nezabudnem na:

sudo systemctl daemon-reload
sudo systemctl restart docker

Log Docker daemonu môžem skontrolovať:

sudo journalctl -u docker -n 100 --no-pager

8.2 Docker po zmene konfigurácie nenabehne

Ak sa Docker po zmene daemon.json alebo systemd override nespustí, prvým krokom je overenie syntaxe:

sudo dockerd --validate \
  --config-file=/etc/docker/daemon.json

Správny výsledok:

configuration OK

Následne:

sudo systemctl status docker --no-pager

a:

sudo journalctl -u docker -n 100 --no-pager

Častým problémom môže byť napríklad konflikt medzi:

/etc/docker/daemon.json

a parametrami použitými priamo v:

ExecStart=

V mojom prípade som preto parameter hosts nepridával do daemon.json, ale TCP listener som definoval cez systemd override.

8.3 tlsv13 alert certificate required

Ak pri teste:

curl \
  --cacert docker-ca.pem \
  https://10.10.8.4:2376/_ping

dostanem:

tlsv13 alert certificate required

nie je to chyba.

Práve naopak — znamená to, že Docker daemon vyžaduje klientsky certifikát.

Správny test musí obsahovať:

curl \
  --cacert docker-ca.pem \
  --cert watchtower-cert.pem \
  --key watchtower-key.pem \
  https://10.10.8.4:2376/_ping

Výsledok:

ok

Tým máme potvrdené, že mTLS funguje.

8.4 Chyba certifikátu alebo nesprávny SAN

Ak Watchtower alebo curl odmietne serverový certifikát, skontrolujem jeho Subject Alternative Name:

openssl x509 \
  -in docker-10.10.8.4-cert.pem \
  -noout -text |
  grep -A2 "Subject Alternative Name"

Pre prvý host očakávam napríklad:

IP Address:10.10.8.4
DNS:mail-ibasterisk

Pre druhý:

IP Address:10.10.8.5
DNS:mon.ibasterisk.local

Ak sa Watchtower pripája cez IP adresu:

10.10.8.4

musí byť táto IP uvedená v SAN.

Nestačí mať iba:

CN=10.10.8.4

8.5 Overenie, že certifikát patrí k privátnemu kľúču

Pri pochybnostiach môžem porovnať verejný kľúč certifikátu:

sudo openssl x509 \
  -in /etc/docker/tls/server-cert.pem \
  -pubkey -noout |
  sha256sum

s verejným kľúčom odvodeným z privátneho kľúča:

sudo openssl pkey \
  -in /etc/docker/tls/server-key.pem \
  -pubout |
  sha256sum

Obidve hodnoty musia byť rovnaké.

8.6 Watchtower sa nevie pripojiť k vzdialenému Docker hostu

Najskôr otestujem Docker API priamo z centrálneho servera:

curl \
  --cacert /etc/watchtower-pki/docker-ca.pem \
  --cert /etc/watchtower-pki/watchtower-cert.pem \
  --key /etc/watchtower-pki/watchtower-key.pem \
  https://10.10.8.4:2376/_ping

Ak dostanem:

ok

sieťová a TLS vrstva funguje.

Potom skontrolujem Watchtower:

sudo docker logs watchtower-84 --tail 100

a environment:

sudo docker inspect watchtower-84 \
  --format '{{range .Config.Env}}{{println .}}{{end}}' |
  grep -E '^DOCKER_'

Očakávam:

DOCKER_HOST=tcp://10.10.8.4:2376
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=/certs

8.7 Kontrola certifikátov namountovaných do Watchtoweru

Bind mounty môžem skontrolovať pomocou:

sudo docker inspect watchtower-84 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

Očakávam napríklad:

/etc/watchtower-pki/docker-ca.pem -> /certs/ca.pem
/etc/watchtower-pki/watchtower-cert.pem -> /certs/cert.pem
/etc/watchtower-pki/watchtower-key.pem -> /certs/key.pem

Rovnako by mali byť pripojené aj notifikačné súbory:

/etc/watchtower-notify/notification-url.txt -> /notify/notification-url.txt
/etc/watchtower-notify/update-template.txt -> /notify/update-template.txt

8.8 docker exec watchtower-84 sh nefunguje

Pri debugovaní som skúsil:

sudo docker exec watchtower-84 sh

ale Watchtower image neobsahuje klasický shell.

Preto sa konfigurácia nekontroluje vstupom do kontajnera, ale pomocou:

docker inspect
sudo docker inspect watchtower-84

alebo cielene:

sudo docker inspect watchtower-84 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

8.9 Watchtower kontajner neaktualizuje

Ak sa kontajner neaktualizuje, najskôr skontrolujem jeho label:

sudo docker inspect element \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Správny výsledok:

true

Ak sa nezobrazí nič, Watchtower ho pri zapnutom:

WATCHTOWER_LABEL_ENABLE: "true"

ignoruje.

Label musí byť pridaný priamo do Compose konfigurácie:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

a následne treba kontajner znovu vytvoriť:

sudo docker compose up -d

8.10 Watchtower hlási Current container not cached for cleanup

Pri vzdialenom Docker daemon-e sa v logu môže objaviť upozornenie podobné:

Current container not cached for cleanup

V tomto nasadení je to očakávané.

Watchtower samotný beží na:

10.10.8.6

ale Docker daemon, ktorý spravuje, je napríklad:

10.10.8.4

Watchtower teda na vzdialenom Docker hoste nenájde svoj vlastný kontajner.

Táto hláška neznamená, že:

WATCHTOWER_CLEANUP: "true"

nefunguje.

Staré image aktualizovaných aplikácií môže Watchtower na vzdialenom Docker hoste naďalej odstrániť.

8.11 removal of container ... is already in progress

Pri manuálnom testovaní som narazil na chybu:

removal oStalo sa to po tom, čo som počas:f container ... is already in progress

Stalo sa to po tom, čo som počas:

sudo docker exec watchtower-84 /watchtower --run-once

proces prerušil cez:

Ctrl+C

a následne okamžite spustil nový --run-once.

Pôvodný proces už medzitým začal aktualizáciu a druhý proces sa pokúsil pracovať s rovnakým kontajnerom.

Preto je dôležité:

neprerušovať --run-once iba preto, že chvíľu nevypisuje nový text.

Sťahovanie väčších image môže trvať niekoľko minút.

Pred ďalším zásahom skontrolujem:

sudo docker ps -a

potom konkrétny kontajner:

sudo docker inspect changedetection \
  --format 'Status={{.State.Status}} Image={{.Image}}'

a aktuálny image:

sudo docker image inspect \
  dgtlmoon/changedetection.io:latest \
  --format '{{.Id}}'

Ak kontajner:

Status=running

a používa aktuálny image, aktualizácia už pravdepodobne prebehla.

8.12 Watchtower chvíľu nič nevypisuje

To nemusí znamenať, že zamrzol.

Pri väčšom image, napríklad:

browserless/chrome

môže sťahovanie trvať dlhšie.

V inom termináli môžem sledovať napríklad:

sudo docker ps

alebo stav image na vzdialenom Docker hoste:

sudo docker images

Najbezpečnejšie je nechať --run-once dokončiť.

8.13 E-mailová notifikácia nepríde

Najskôr overím SMTP server ešte mimo Watchtoweru:

openssl s_client \
  -starttls smtp \
  -connect mail.ibasterisk.eu:587 \
  -servername mail.ibasterisk.eu \
  -verify_return_error

TLS spojenie musí prebehnúť úspešne.

Následne skontrolujem existenciu secretu:

sudo ls -l \
  /etc/watchtower-notify/notification-url.txt

Práva by mali byť:

-rw------- root root

Obsah súboru nepublikujem ani nevypisujem, pretože obsahuje SMTP App Password.

Skontrolujem mount:

sudo docker inspect watchtower-84 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

a environment:

sudo docker inspect watchtower-84 \
  --format '{{range .Config.Env}}{{println .}}{{end}}' |
  grep '^WATCHTOWER_NOTIFICATION'

8.14 Bezpečný SMTP test

SMTP môžem otestovať bez reálnej aktualizácie kontajnera:

sudo docker exec \
  -e WATCHTOWER_NOTIFICATION_TEMPLATE_FILE= \
  watchtower-84 \
  /watchtower \
  --run-once \
  --monitor-only \
  --notification-template 'Watchtower SMTP TEST - docker 10.10.8.4' \
  element

Pri úspechu sa v logu objaví napríklad:

Shoutrrr: Mail successfully sent to "updater@ibasterisk.eu"!

Pre druhý host:

sudo docker exec \
  -e WATCHTOWER_NOTIFICATION_TEMPLATE_FILE= \
  watchtower-85 \
  /watchtower \
  --run-once \
  --monitor-only \
  --notification-template 'Watchtower SMTP TEST - docker 10.10.8.5' \
  grafana

Parameter:

--monitor-only

zabezpečí, že počas testu nedôjde k aktualizácii kontajnera.

8.15 Po aktualizácii aplikácia nefunguje

Watchtower môže technicky vykonať aktualizáciu úspešne, ale samotná aplikácia môže mať problém s novou verziou.

Preto kontrolujem:

sudo docker ps

a log aplikácie:

sudo docker logs <container> --tail 100

Napríklad:

sudo docker logs element --tail 100

alebo:

sudo docker logs grafana --tail 100

Dôležité je tiež overiť samotnú aplikáciu cez webové rozhranie.

Práve preto automaticky neaktualizujem kritické služby a databázy, pri ktorých môže nová verzia vyžadovať migráciu.

8.16 Kontajner používa nový image?

Aktuálny image použitý kontajnerom:

sudo docker inspect changedetection \
  --format '{{.Image}}'

ID image dostupného pod tagom:

sudo docker image inspect \
  dgtlmoon/changedetection.io:latest \
  --format '{{.Id}}'

Ak sú hodnoty rovnaké, kontajner používa aktuálne stiahnutý image.

8.17 Rýchla diagnostika

Ak niečo nefunguje, praktický postup je kontrolovať riešenie postupne od najnižšej vrstvy:

Takýto postup je lepší ako náhodne meniť viacero častí konfigurácie naraz.

Výsledok

Po vyriešení týchto bodov máme pomerne jednoducho diagnostikovateľné riešenie.

Najdôležitejšie je oddeliť jednotlivé vrstvy:

Ak každú vrstvu otestujeme samostatne, väčšina problémov sa dá lokalizovať pomerne rýchlo.

9. Záver

Cieľom celého riešenia bolo vytvoriť centrálne a zároveň bezpečne riadené automatické aktualizácie Docker kontajnerov bez toho, aby som musel nasadzovať Watchtower na každý Docker host samostatne.

Výsledná architektúra používa centrálny server 10.10.8.6, na ktorom bežia dve nezávislé Watchtower inštancie. Tie sa cez mTLS pripájajú k vzdialeným Docker daemon-om na 10.10.8.4 a 10.10.8.5.

Automatické aktualizácie sú povolené iba pre explicitne označené kontajnery pomocou labelu:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

Vďaka tomu zostávajú kritické služby, databázy a infraštruktúrne komponenty mimo automatického update procesu a môžu byť aktualizované riadeným spôsobom po kontrole release notes a vytvorení zálohy.

Komunikácia s Docker API je zabezpečená pomocou vlastnej certifikačnej autority a obojstranne overovaného TLS spojenia. Docker daemon teda neprijme klienta bez platného certifikátu, čo výrazne znižuje riziko zneužitia vzdialeného API.

Súčasťou riešenia sú aj SMTP notifikácie. Watchtower neposiela e-mail pri každej kontrole, ale iba v prípade úspešnej aktualizácie alebo chyby. Výsledkom je menej zbytočných správ a zároveň okamžitá informácia v prípade, že sa na niektorom Docker hoste niečo zmení.

Výsledný proces je teda:

Takto mám aktualizácie vybraných Docker služieb automatizované, ale zároveň zostáva zachovaná kontrola nad tým, čo sa môže aktualizovať automaticky a čo musí zostať manuálne spravované.

Celé riešenie kombinuje:

Docker
Watchtower
mTLS
vlastnú Docker CA
label-only aktualizácie
cleanup starých image
SMTP cez STARTTLS
App Password
e-mailové reporty

Výsledkom je jednoduchý, centrálne spravovaný a relatívne bezpečný spôsob automatizácie aktualizácií Docker kontajnerov vo vlastnej infraštruktúre.

BookStack na Ubuntu 26.04 Server Docker

BookStack je jednoduchá open-source platforma určená na tvorbu internej dokumentácie, manuálov, postupov a znalostnej databázy.

V tomto návode si ukážeme inštaláciu BookStack pomocou Docker Compose, databázy MariaDB a následné sprístupnenie cez internú doménu s HTTPS certifikátom vystaveným pomocou FreeIPA CA.

Čo budeme potrebovať?

Na inštaláciu budeme potrebovať:

  • Linux server s Dockerom a Docker Compose
  • približne 2 GB RAM
  • niekoľko GB voľného diskového priestoru
  • interný DNS záznam
  • MariaDB databázu
  • SSL certifikát
  • funkčný systémový čas / NTP

V tomto návode budeme používať:

bookstack.example.local

a ukážkovú IP adresu:

192.0.2.10

Tieto hodnoty nahraďte vlastnou internou doménou a IP adresou servera.

Vytvorenie pracovného adresára

mkdir -p ~/bookstack
cd ~/bookstack

Vytvorenie APP_KEY

BookStack vyžaduje aplikačný šifrovací kľúč.

Pri použití LinuxServer.io image ho môžeme vygenerovať:

docker run --rm \
  --entrypoint /bin/bash \
  lscr.io/linuxserver/bookstack:latest \
  appkey

Výstup bude vyzerať približne:

base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Tento kľúč si uložíme do súboru .env.

Vytvorenie databázových hesiel

Vygenerujeme náhodné heslá:

DBPASS="$(openssl rand -hex 32)"
ROOTPASS="$(openssl rand -hex 32)"

Vytvoríme:

nano .env

Obsah:

APP_KEY=base64:SEM_VLOZTE_VYGENEROVANY_APP_KEY
BOOKSTACK_DB_PASSWORD=SEM_VLOZTE_DB_HESLO
BOOKSTACK_DB_ROOT_PASSWORD=SEM_VLOZTE_ROOT_DB_HESLO

Po vytvorení súbor zabezpečíme:

chmod 600 .env

Ak používame Git:

echo '.env' >> .gitignore

Súbor .env obsahuje citlivé údaje a nemal by byť publikovaný ani uložený vo verejnom Git repozitári.

Docker Compose

Vytvoríme:

nano docker-compose.yml

a vložíme:

services:
  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    restart: unless-stopped

    ports:
      - "192.0.2.10:6875:80"

    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Bratislava

      - APP_URL=https://bookstack.example.local
      - APP_KEY=${APP_KEY}

      - DB_HOST=bookstack-db
      - DB_PORT=3306
      - DB_USERNAME=bookstack
      - DB_PASSWORD=${BOOKSTACK_DB_PASSWORD}
      - DB_DATABASE=bookstackapp

    depends_on:
      - bookstack-db

    volumes:
      - bookstack_config:/config


  bookstack-db:
    image: lscr.io/linuxserver/mariadb:latest
    container_name: bookstack-db
    restart: unless-stopped

    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Bratislava

      - MYSQL_ROOT_PASSWORD=${BOOKSTACK_DB_ROOT_PASSWORD}
      - MYSQL_DATABASE=bookstackapp
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=${BOOKSTACK_DB_PASSWORD}

    volumes:
      - bookstack_db_config:/config


volumes:
  bookstack_config:
  bookstack_db_config:

Použitím Docker volumes zabezpečíme, že konfigurácia BookStacku a databáza zostanú zachované aj po vytvorení nového kontajnera.

Kontrola konfigurácie

sudo docker compose config >/dev/null && echo "COMPOSE OK"

Správny výsledok:

COMPOSE OK

Stiahnutie Docker images

sudo docker compose pull

Spustenie BookStack

sudo docker compose up -d

Stav kontajnerov:

sudo docker compose ps

Mali by sme vidieť:

bookstack       Up
bookstack-db    Up

Kontrola webovej aplikácie

BookStack môžeme pred konfiguráciou HTTPS otestovať:

curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \
http://192.0.2.10:6875/

Funkčná aplikácia môže odpovedať napríklad:

HTTP 302

Ide o presmerovanie na webové rozhranie alebo prihlasovaciu stránku.

Interný DNS záznam

V internom DNS vytvoríme A záznam:

bookstack.example.local → 192.0.2.10

Ak používame FreeIPA DNS, záznam môžeme vytvoriť priamo v administrácii FreeIPA.

SSL certifikát z FreeIPA

Keďže používame internú .local doménu, verejný Let’s Encrypt certifikát nie je vhodný.

SSL certifikát preto vystavíme pomocou internej FreeIPA CA.

Certifikát by mal obsahovať:

CN  = bookstack.example.local
SAN = DNS:bookstack.example.local

Výsledkom budú napríklad súbory:

bookstack.example.local.key
bookstack.example.local.pem
ca.crt

Klientske zariadenia musia dôverovať FreeIPA CA, aby sa HTTPS stránka zobrazovala bez bezpečnostného upozornenia.

Reverse proxy

Pred BookStack môžeme umiestniť Nginx reverse proxy.

Príklad konfigurácie:

server {
    listen 80;
    server_name bookstack.example.local;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name bookstack.example.local;

    ssl_certificate /etc/nginx/ssl/bookstack.example.local.pem;
    ssl_certificate_key /etc/nginx/ssl/bookstack.example.local.key;

    location / {
        proxy_pass http://192.0.2.10:6875;

        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Po zmene konfigurácie skontrolujeme syntax:

sudo nginx -t

A následne Nginx reštartujeme:

sudo systemctl restart nginx

Finálny prístup

Po dokončení konfigurácie bude BookStack dostupný na:

https://bookstack.example.local

Prvé prihlásenie je

Meno: admin@admin.com
Heslo: password

V docker-compose.yml musí byť zároveň nastavené:

APP_URL=https://bookstack.example.local

Ak túto hodnotu zmeníme až po prvom spustení, BookStack kontajner znova vytvoríme:

sudo docker compose up -d --force-recreate bookstack

Kontrola kontajnerov

sudo docker compose ps

Log aplikácie:

sudo docker logs --tail 100 bookstack

Pri úspešnom spustení môžeme vidieť napríklad:

INFO  Nothing to migrate.
[ls.io-init] done.

Zálohovanie

Pri zálohovaní BookStack je potrebné uchovávať minimálne:

BookStack /config
MariaDB /config
docker-compose.yml
.env

Súbor .env obsahuje APP_KEY a databázové heslá a musí byť uložený bezpečne.

APP_KEY je obzvlášť dôležitý. Pri obnove existujúcej BookStack inštalácie by mal byť použitý rovnaký APP_KEY ako v pôvodnej inštalácii.

Passbolt na Ubuntu 26.04 Server Docker

Passbolt je open-source správca hesiel určený najmä pre tímy a firmy. Umožňuje bezpečne ukladať, zdieľať a spravovať prihlasovacie údaje pomocou OpenPGP šifrovania, pričom každý používateľ pracuje s vlastným privátnym kľúčom a passphrase.

Technické požiadavky Passbolt

CPU2 jadrá2–4 jadrá
RAM2 GB4 GB
Disk20 GB30–50 GB podľa počtu používateľov a backupov
Sieť10 Mbps100 Mbps alebo viac
InternetÁnoÁno
Čas/NTPVyžadovanýNTP musí byť funkčné
SMTPPotrebný pre notifikácie a recoveryOdporúčaný
HTTPSOdporúčaný / produkčne nutnýTLS certifikát + FQDN

Kde je možné Passbolt nainštalovať

Passbolt aktuálne poskytuje oficiálne inštalačné postupy pre:

PlatformaPodpora
Docker / Docker ComposeCE / Pro
Ubuntu 24.04CE / Pro
Debian 13CE / Pro
Red Hat Enterprise Linux 9CE / Pro
AlmaLinux 9CE / Pro
Rocky Linux 9CE / Pro
Oracle Linux 9CE / Pro
OpenSUSE Leap 15CE / Pro
SUSE Linux Enterprise Server 15 SP6CE / Pro
Raspberry PiCE / Pro
Kubernetes / Helm ChartCE / Pro
AWS AMICE / Pro
DigitalOceanCE
Virtual AppliancePro
Inštalácia zo zdrojového kóduCE

Poznámka: Oficiálny balíčkový návod Passbolt je aktuálne dostupný pre Ubuntu 24.04. V tomto návode používame Ubuntu 26.04 ako Docker host, pričom samotný Passbolt beží v oficiálnom Docker kontajneri. Preto nie sme závislí od balíčkovej inštalácie Passbolt určenej pre konkrétnu verziu Ubuntu.

Čo budeme potrebovať?

Na inštaláciu budeme potrebovať Linux server s nainštalovaným Dockerom a Docker Compose, vlastnú doménu, DNS záznam smerujúci na reverse proxy, SMTP server pre odosielanie notifikácií a správne nastavený systémový čas.

V tomto návode používam samostatný príkaz:

docker-compose

Ak používate novší Docker Compose plugin, môžete namiesto neho používať:

docker compose

Pre produkčné prostredie je vhodné použiť konkrétnu verziu Passbolt image namiesto pohyblivého tagu latest. Passbolt to odporúča aj vo svojej dokumentácii.

Predpríprava

Vytvoríme pracovný adresár:

mkdir passbolt
cd passbolt

Vygenerujeme náhodné 64-znakové heslo pre databázového používateľa:

DBPASS="$(openssl rand -hex 32)"

Uložíme ho do skrytého súboru .env:

printf 'PASSBOLT_DB_PASSWORD=%s\n' "$DBPASS" > .env

Dočasnú premennú odstránime zo shellu:

unset DBPASS

Nastavíme práva:

chmod 600 .env
echo '.env' >> .gitignore

Bezpečnostné upozornenie: Súbor .env obsahuje databázové a SMTP heslo. Nastavte mu práva 600, nevkladajte ho do verejného Git repozitára a jeho obsah nezverejňujte.

Správnosť môžeme skontrolovať bez vypísania hesla:

awk -F= '/^PASSBOLT_DB_PASSWORD=/{print "Heslo v .env ma dlzku:", length($2)}' .env

Výsledok:

Heslo v .env ma dlzku: 64

Súbor .env je skrytý. Zobrazíme ho napríklad:

ls -la

SMTP heslo

Ak chceme používať e-mailové notifikácie, pridáme do .env ešte SMTP heslo alebo App Password:

PASSBOLT_DB_PASSWORD=<VYGENEROVANE_DB_HESLO>
PASSBOLT_SMTP_PASSWORD=<SMTP_APP_PASSWORD>

Skutočné heslá nikdy nevkladajte do verejnej dokumentácie alebo Git repozitára.

Passbolt podporuje SMTP konfiguráciu pomocou environment premenných vrátane hosta, portu, používateľa, hesla, odosielateľa a TLS.

Docker-compose.yml

Príklad verejnej konfigurácie:

nano docker-compose.yml
services:
  passbolt-db:
    image: mariadb:10.11
    container_name: passbolt-db
    restart: unless-stopped

    environment:
      MYSQL_RANDOM_ROOT_PASSWORD: "true"
      MYSQL_DATABASE: "passbolt"
      MYSQL_USER: "passbolt"
      MYSQL_PASSWORD: "${PASSBOLT_DB_PASSWORD}"

    volumes:
      - passbolt_database:/var/lib/mysql

    networks:
      - passbolt-network


  passbolt:
    image: passbolt/passbolt:5.15.0-1-ce
    container_name: passbolt
    restart: unless-stopped

    depends_on:
      - passbolt-db

    environment:
      # URL aplikácie
      APP_FULL_BASE_URL: "https://passbolt.example.com"

      # Reverse proxy
      PASSBOLT_SECURITY_PROXIES_ACTIVE: "true"

      # Databáza
      DATASOURCES_DEFAULT_HOST: "passbolt-db"
      DATASOURCES_DEFAULT_USERNAME: "passbolt"
      DATASOURCES_DEFAULT_PASSWORD: "${PASSBOLT_DB_PASSWORD}"
      DATASOURCES_DEFAULT_DATABASE: "passbolt"

      # SMTP
      EMAIL_DEFAULT_FROM_NAME: "Passbolt"
      EMAIL_DEFAULT_FROM: "passbolt@example.com"

      EMAIL_TRANSPORT_DEFAULT_HOST: "mail.example.com"
      EMAIL_TRANSPORT_DEFAULT_PORT: "587"
      EMAIL_TRANSPORT_DEFAULT_USERNAME: "passbolt@example.com"
      EMAIL_TRANSPORT_DEFAULT_PASSWORD: "${PASSBOLT_SMTP_PASSWORD}"
      EMAIL_TRANSPORT_DEFAULT_TLS: "true"

      # GPG
      PASSBOLT_KEY_NAME: "Passbolt Server"
      PASSBOLT_KEY_EMAIL: "passbolt@example.com"

      TZ: "Europe/Bratislava"

    volumes:
      - passbolt_gpg:/etc/passbolt/gpg
      - passbolt_jwt:/etc/passbolt/jwt

    command:
      [
        "/usr/bin/wait-for.sh",
        "-t",
        "0",
        "passbolt-db:3306",
        "--",
        "/docker-entrypoint.sh"
      ]

    ports:
      - "192.0.2.10:8088:80"

    networks:
      - passbolt-network


volumes:
  passbolt_database:
  passbolt_gpg:
  passbolt_jwt:


networks:
  passbolt-network:
    driver: bridge

Nastavenie IP adresy

V ukážkovej konfigurácii používame adresu:

192.0.2.10

Túto adresu je potrebné nahradiť LAN IP adresou servera, na ktorom beží Passbolt.

Ak reverse proxy beží na rovnakom serveri ako Passbolt, odporúčame publikovať port iba na localhost:

ports:
  - "127.0.0.1:8088:80"

Ak reverse proxy beží na inom serveri, musí byť použitá LAN IP Passbolt servera.

PASSBOLT_SECURITY_PROXIES_ACTIVE=true aktivuje podporu reverse proxy a Passbolt ju odporúča, ak je aplikácia umiestnená za proxy/load balancerom.

Kontrola konfigurácie

sudo docker-compose config >/dev/null && echo "COMPOSE OK"

Správny výsledok:

COMPOSE OK

Stiahnutie Docker images

Príkaz:

sudo docker-compose pull

stiahne images definované v docker-compose.yml, ale ešte samotné kontajnery nespustí.

Napríklad:

[+] pull 22/22
 ✔ Image mariadb:10.11                 Pulled                                                                                                                                     11.9s
 ✔ Image passbolt/passbolt:5.15.0-1-ce Pulled     

Spustenie Passbolt

sudo docker-compose up -d

Stav skontrolujeme:

sudo docker-compose ps

Mali by sme vidieť oba kontajnery:

Výstup:

passbolt       Up
passbolt-db    Up

Port Passbolt servera bude mapovaný napríklad:

192.0.2.10:8088 -> 80/tcp

Test webovej aplikácie

Namiesto:

curl -I http://192.0.2.10:8088

je vhodnejšie použiť normálny HTTP GET:

curl -v http://192.0.2.10:8088/

Pri funkčnom Passbolte môžeme dostať:

HTTP/1.1 302 Found
location: /auth/login?redirect=%2F

Login stránku môžeme otestovať:

curl -v http://192.0.2.10:8088/auth/login

Správna odpoveď:

HTTP/1.1 200 OK

Dôležitá poznámka: Passbolt používa hodnotu APP_FULL_BASE_URL, preto môže pri priamom otvorení cez IP adresu vyzerať stránka nesprávne alebo zostať biela. Finálny prístup má prebiehať cez adresu:

https://passbolt.example.com

SMTP konfigurácia

V našom príklade používame:

SMTP server: mail.example.com
Port: 587
Encryption: STARTTLS
Username: passbolt@example.com

Port 587 s EMAIL_TRANSPORT_DEFAULT_TLS=true je podporovaný Passbolt konfiguráciou pre STARTTLS.

Po úprave .env alebo docker-compose.yml je potrebné Passbolt kontajner znova vytvoriť:

sudo docker-compose up -d --force-recreate passbolt

Overíme, či Passbolt premenné načítal bez zobrazenia hesla:

sudo docker exec passbolt sh -c '
echo "FROM=$EMAIL_DEFAULT_FROM"
echo "HOST=$EMAIL_TRANSPORT_DEFAULT_HOST"
echo "PORT=$EMAIL_TRANSPORT_DEFAULT_PORT"
echo "USER=$EMAIL_TRANSPORT_DEFAULT_USERNAME"
echo "TLS=$EMAIL_TRANSPORT_DEFAULT_TLS"

if [ -n "$EMAIL_TRANSPORT_DEFAULT_PASSWORD" ]; then
  echo "SMTP PASSWORD=SET"
else
  echo "SMTP PASSWORD=EMPTY"
fi
'

Výsledok môže byť:

FROM=passbolt@example.com
HOST=mail.example.com
PORT=587
USER=passbolt@example.com
TLS=true
SMTP PASSWORD=SET

Test odoslania e-mailu

sudo docker exec passbolt \
  su -s /bin/bash -c \
  "source /etc/environment && cd /usr/share/php/passbolt && ./bin/cake passbolt send_test_email --recipient=admin@example.com" \
  www-data

Ak sa namiesto nakonfigurovaného SMTP servera zobrazí localhost, port 25 alebo SMTP PASSWORD=EMPTY, skontrolujte, či sú SMTP premenné umiestnené pod službou passbolt v časti environment: a či je PASSBOLT_SMTP_PASSWORD správne definovaný v súbore .env.

Passbolt poskytuje send_test_email práve na diagnostiku SMTP konfigurácie.

Ak je konfigurácia správna, testovací e-mail príde z adresy:

passbolt@example.com

Reverse proxy

Ak používame napríklad Mailcow Nginx ako reverse proxy na inom serveri, backend bude smerovať na:

http://192.0.2.10:8088

Príklad Nginx konfigurácie:

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name passbolt.example.com;

    ssl_certificate /etc/ssl/mail/cert.pem;
    ssl_certificate_key /etc/ssl/mail/key.pem;

    client_max_body_size 0;

    location ^~ /.well-known/acme-challenge/ {
        allow all;
        default_type "text/plain";
        root /web;
    }

    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }

    location / {
        proxy_pass http://192.0.2.10:8088;

        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_redirect off;
    }
}

Mailcow umožňuje vytvárať persistentné vlastné Nginx konfigurácie v data/conf/nginx/ a používať ich ako reverse proxy na vzdialený backend.

Kontrola Nginx konfigurácie

Po vytvorení alebo úprave reverse proxy konfigurácie skontrolujeme syntax Nginx:

cd /opt/mailcow-dockerized

sudo docker-compose exec nginx-mailcow nginx -t

Správny výsledok:

syntax is ok
test is successful

Ak je konfigurácia v poriadku, reštartujeme Nginx kontajner:

sudo docker-compose restart nginx-mailcow

SSL certifikát v Mailcow

Doménu Passbolt pridáme do:

ADDITIONAL_SAN=passbolt.example.com

Ak už ADDITIONAL_SAN obsahuje ďalšie domény:

ADDITIONAL_SAN=video.example.com,jelly.example.com,passbolt.example.com

Bez medzier a bez úvodzoviek. Mailcow tým pridá hostname do SAN certifikátu.

Aplikujeme konfiguráciu:

Po úspešnom nastavení reverse proxy a SSL certifikátu by sme už mali na adrese https://passbolt.example.com vidieť úvodnú obrazovku Passbolt. Prvého administrátora však ešte najskôr vytvoríme pomocou CLI.

sudo docker-compose up -d

V prípade potreby môžeme vynútiť obnovenie certifikátu:

sudo touch data/assets/ssl/force_renew
sudo docker-compose restart acme-mailcow

Log:

sudo docker-compose logs --tail=200 -f acme-mailcow

Pri samostatnom custom webe/reverse proxy nie je potrebné automaticky pridávať hostname do ADDITIONAL_SERVER_NAMES; Mailcow na to pri custom web root konfiguráciách výslovne upozorňuje.

Kontrola Passbolt – Healthcheck

Pred vytvorením prvého administrátora môžeme skontrolovať celkový stav Passbolt:

sudo docker exec passbolt \
  su -s /bin/bash -c \
  "source /etc/environment && cd /usr/share/php/passbolt && ./bin/cake passbolt healthcheck --hide-pass" \
  www-data

Healthcheck pomôže odhaliť problémy s databázou, GPG kľúčmi, konfiguráciou, URL aplikácie alebo ďalšími komponentmi Passbolt.

Vytvorenie prvého administrátora

Keď už funguje:

https://passbolt.example.com

vytvoríme prvého administrátora:

sudo docker-compose exec passbolt \
  su -m -c "/usr/share/php/passbolt/bin/cake \
  passbolt register_user \
  -u admin@example.com \
  -f Admin \
  -l User \
  -r admin" \
  -s /bin/sh www-data

Passbolt nevypíše iba „kód“, ale jednorazový registračný URL link, napríklad:

https://passbolt.example.com/setup/install/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy

Tento odkaz je citlivý. Nezverejňujte ho v dokumentácii, tiketoch ani diskusiách. Otvorte ho priamo v prehliadači a dokončite vytvorenie používateľského profilu, GPG kľúča a recovery kitu.

Inštalácia FreeIPa v Docker Ubuntu Server 26.04 LTS.

Úvod

Pred nedávnom som sa rozhodol, že si urobím vlastný doménový radič, a postavil som si FreeIPA. Zvolil som si Raspberry Pi 4 so 4 GB RAM a SSD disk, ako operačný systém som si zvolil Ubuntu Server 26.04 LTS.

Čo je to FreeIPA a na čo slúži?

FreeIPA (Identity, Policy, Audit) je integrované riadiace centrum pre správu identity a prístupov v sieťových prostrediach. Jednoducho povedané, ide o Linuxovú alternatívu k Microsoft Active Directory.

Hlavné úlohy a výhody FreeIPA:

  • Centralizovaná správa používateľov (Single Sign-On): Používateľa vytvoríte na jednom mieste vo FreeIPA a ten sa pomocou rovnakého mena a hesla dokáže prihlásiť do všetkých počítačov, serverov a webových aplikácií v sieti.
  • Bezpečné overovanie (Kerberos): Používa protokol Kerberos na bezpečné prihlasovanie bez toho, aby sa heslo posielalo po sieti v nekrytej podobe.
  • Centrálny adresár (LDAP): Slúži ako štruktúrovaná databáza všetkých používateľov, skupín, počítačov a ich oprávnení.
  • Správa certifikátov (Certifikačná autorita – CA): Obsahuje vlastnú certifikačnú autoritu, ktorá dokáže automaticky generovať a spravovať SSL/TLS certifikáty pre služby v sieti.
  • Riadenie prístupov a pravidiel (SUDO & HBAC): Umožňuje presne určiť, ktorý používateľ sa môže prihlásiť na konkrétny server a aké príkazy tam môže spúšťať s administrátorskými právami.

Technické parametre


Parameter Minimálne požiadavky Odporúčané (Produkcia) Tvoja konfigurácia
Procesor (CPU) 2 jadrá (ARM64 / x86_64) 4+ jadier ARM64 (Raspberry Pi)
Pamäť (RAM) 2 GB (s --skip-mem-check) 4 GB – 8 GB Podľa servera
Úložisko (Disk) 10 GB (SSD) 30 GB+ (SSD / NVMe) SSD
Swap pamäť 2 GB 4 GB Nastavený v Ubuntu
Operačný systém Ubuntu Server (64-bit) Ubuntu Server LTS Ubuntu Server
Kontajnerový systém Docker + Docker Compose v2 Docker + Docker Compose v2 Docker Compose v2

Príprava inštalácie

Ako prvé urobíme aktualizáciu zoznamu balíčkov a nasledne upgrade

sudo apt update
sudo apt upgrade

Nainštalujeme Dockeru a Docker Compose pluginu

sudo apt install -y docker.io docker-compose-v2

Povolíme a spustíme služby Docker

sudo systemctl enable --now docker

Inštalácia

Vytvoreríme Docker Compose konfiguráciu, pomocou textového edita, vim, nano, alebo vi vložíme text a uložíme ho. Ak chceme zmeniť užívateľské meno a heslo, tak to samozrejme vieme urobiť.

mkdir ~/freeipa-docker && cd ~/freeipa-docker
nano docker-compose.yml
services:
  freeipa:
    image: freeipa/freeipa-server:fedora-rawhide
    container_name: freeipa-server
    hostname: freeipa.ibasterisk.local
    domainname: ibasterisk.local
    tty: true
    stdin_open: true
    network_mode: host
    restart: unless-stopped
    privileged: true
    cgroup: host
    environment:
      - IPA_SERVER_IP=10.10.8.6
      - TZ=Europe/Bratislava
    volumes:
      - /var/lib/freeipa-data:/data:Z
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
    tmpfs:
      - /run
      - /tmp
      - /run/lock
    command:
      - --realm=IBASTERISK.LOCAL
      - --ds-password=TvojeSilneHeslo123!
      - --admin-password=TvojeSilneHeslo123!
      - --unattended
      - --no-ntp
      - --skip-mem-check

Inštaláciu kontajnera urobíme následovne

sudo docker compose up -d

Nechajte tomu čas nech sa nainštaluje. Môže to trvať aj probližne 10 minút

V tejto dokumentácií je aj užívateľske meno a heslo

admin
TvojeSilneHeslo123!

Riešenie problémov

Ak sa pokúsite otvoriť webovú službu, je možné, že Vám to fungovať nebude. Je potrebné potrebné pridať DNS záznam, buď máte vlastný DNS server napr. Pi-hole, alebo DNS Vám robí nejaký iný server, ak nemáte, tak v prostredí Windows je potrebné ísť

C:\Windows\System32\drivers\etc\hosts

Na spodok je potrebné pridať IP adresu servera, kde je nainštalovaná FreeIPA a hostname pre príklad

10.10.8.6 freeipa.ibasterisk.local

V prostedí Linux príklad

sudo nano /etc/hosts
10.10.8.6 freeipa.ibasterisk.local freeipa

Vlastná evidencia serverových služieb v Dockeri

Úvod:

Pri viacerých lokálnych serveroch, Docker kontajneroch a webových službách som potreboval jednoduchý prehľad o tom, kde mi čo beží. Pôvodne som mal služby evidované v Excel tabuľke, ale časom začalo byť nepraktické stále ručne kontrolovať IP adresy, porty a dostupnosť jednotlivých služieb.

Preto som si vytvoril jednoduchú webovú aplikáciu Server Evidence, ktorá slúži ako lokálny dashboard pre evidenciu serverových služieb.

Aplikácia beží v Dockeri na serveri MON a zobrazuje prehľad služieb, IP adries, portov, URL adries, poznámok a stavu služby Online alebo Offline.

Umiestnenie aplikácie:

Aplikácia je spustená na serveri MON.

IP adresa servera: 10.10.8.5
Port aplikácie: 3030
URL aplikácie: http://10.10.8.5:3030
Názov kontajnera: server-evidence

Projekt je uložený v priečinku:

/home/ivan/server-evidence

Štruktúra projektu:

server-evidence/
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
├── app.py
├── services.yml
├── static/
│   └── favicon.ico
└── templates/
    └── index.html

Význam jednotlivých súborov a priečinkov:

Dockerfile

Súbor, podľa ktorého sa vytvára Docker image aplikácie. Obsahuje inštaláciu Python závislostí, kopírovanie aplikácie a spustenie Flask servera.

docker-compose.yml

Hlavný Docker Compose súbor. Definuje kontajner server-evidence, mapovanie portu 3030:5000, pripojenie súboru services.yml a automatický reštart kontajnera.

app.py

Hlavný Python súbor aplikácie. Načítava služby zo súboru services.yml, kontroluje ich dostupnosť a posiela údaje do HTML šablóny.

requirements.txt

Zoznam Python balíkov potrebných pre aplikáciu. V tomto prípade hlavne Flask a PyYAML.

services.yml

Najdôležitejší konfiguračný súbor. Obsahuje zoznam serverov, služieb, IP adries, portov, URL adries, kategórií a poznámok.

templates/

Priečinok pre HTML šablóny Flask aplikácie. Nachádza sa v ňom súbor index.html, ktorý zobrazuje tabuľku služieb vo webovom rozhraní.

static/

Priečinok pre statické súbory aplikácie, napríklad favicon ikonu.

Kontrola súborov na serveri

Na serveri je možné štruktúru projektu overiť príkazom:

cd ~/server-evidence
ls

Výstup:

Dockerfile  docker-compose.yml  services.yml  templates
app.py      requirements.txt    static

Použité technológie:

Aplikácia je vytvorená jednoducho pomocou Pythonu a Flasku. Údaje o službách nie sú uložené v databáze, ale v prehľadnom YAML súbore services.yml.

Použité komponenty:

  • Python
  • Flask
  • PyYAML
  • Docker
  • Docker Compose
  • HTML, CSS a jednoduchý JavaScript

Výhodou tohto riešenia je, že aplikácia je jednoduchá, rýchla a ľahko upraviteľná. Na doplnenie novej služby stačí upraviť jeden súbor.

Docker Compose konfigurácia:

Súbor docker-compose.yml:

services:
  server-evidence:
    build: .
    container_name: server-evidence
    ports:
      - "3030:5000"
    volumes:
      - ./services.yml:/app/services.yml
    restart: unless-stopped

Aplikácia vo vnútri kontajnera počúva na porte 5000, ale na serveri je dostupná cez port 3030.

Dockerfile:

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .
COPY services.yml .
COPY templates ./templates
COPY static ./static

EXPOSE 5000

CMD ["python", "app.py"]

Závislosti aplikácie:

Súbor requirements.txt:

Flask==3.0.3
PyYAML==6.0.2

Hlavný konfiguračný súbor služieb:

Všetky služby sú uložené v súbore:

services.yml

Príklad položky v services.yml:

   - server: "MON"
     ip: "10.10.8.5"
     port: "3030"
     name: "Server Evidence"
     url: "http://10.10.8.5:3030"
     check_url: "http://10.10.8.5:3030"
     category: "Web"
     note: "Lokálna evidencia serverových služieb"

Význam položiek:

server – názov servera alebo skupiny
ip – IP adresa servera alebo názov služby
port – port služby
name – názov služby
url – klikateľný odkaz v aplikácii
check_url – URL adresa použitá na kontrolu dostupnosti
category – kategória služby
note – poznámka k službe

Kontrola stavu služby:

Aplikácia kontroluje, či je služba dostupná. Ak je nastavené check_url, kontroluje sa priamo webová URL adresa. Ak check_url nie je nastavené, aplikácia kontroluje IP adresu a port.

Vďaka tomu viem pri službách okamžite vidieť, či sú Online alebo Offline.

Spustenie aplikácie:

V priečinku projektu:

cd ~/server-evidence
sudo docker-compose up -d --build

Reštart aplikácie:

sudo docker-compose restart server-evidence

Kontrola bežiaceho kontajnera:

sudo docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

Kontrola logov:

sudo docker-compose logs --tail=50

Favicon aplikácie:

Pre aplikáciu bola vytvorená aj vlastná favicon ikona, aby mala aplikácia vlastný vizuálny štýl v prehliadači.

Súbor favicon.ico je uložený v priečinku:

static/favicon.ico

Do HTML šablóny templates/index.html bol do časti head doplnený riadok:

<link rel="icon" type="image/x-icon" href="/static/favicon.ico">

A do Dockerfile bolo potrebné doplniť kopírovanie priečinka static:

COPY static ./static

Po doplnení favicon bolo potrebné aplikáciu znova rebuildnúť:

sudo docker-compose up -d --build

Ak sa favicon nezobrazí hneď, stačí použiť tvrdý refresh v prehliadači alebo otvoriť aplikáciu v anonymnom okne.

Výhody riešenia:

  • Všetky služby sú na jednom mieste.
  • Vidím IP adresy, porty a URL adresy.
  • Aplikácia ukazuje stav Online alebo Offline.
  • Odkazy sú klikateľné.
  • Údaje sa jednoducho upravujú v YAML súbore.
  • Aplikácia beží v Dockeri.
  • Nie je potrebná databáza.
  • Dá sa ľahko zálohovať a preniesť na iný server.

Záver:

Server Evidence mi slúži ako jednoduchá lokálna evidencia serverových služieb. Nahradil som tým pôvodnú Excel tabuľku a získal som prehľadný webový dashboard, kde okamžite vidím, čo mi na jednotlivých serveroch beží.

Do budúcna sa dá aplikácia rozšíriť napríklad o prihlasovanie, editáciu služieb priamo cez web, export do Excelu alebo detailnejší monitoring služieb.

Inštalácia NetBox Docker

Na čo slúži NetBox

NetBox slúži ako centrálna evidencia IT infraštruktúry.
Je to miesto, kde si zapisujem, aké zariadenia mám v sieti, aké majú IP adresy, aký majú účel, kde sa nachádzajú a aké služby na nich bežia.

NetBox nie je monitoring. Nehovorí mi, či server práve spadol alebo či má vysoké CPU. Na to slúži Zabbix.

NetBox odpovedá na otázky typu:

Aké zariadenia mám v sieti?
Akú IP adresu má konkrétny server?
Na ktorom zariadení beží daná služba?
Aký model je dané zariadenie?
Aké má sériové číslo?
Ktorý server je DNS, mail alebo monitoring?
Aké porty/služby sú na serveri spustené?
Typ inštaláciePodporované OSMinimálne požiadavky
NetBox cez DockerLinux server, napr. Ubuntu, Debian, Rocky Linux, AlmaLinux, Fedora, Raspberry Pi OSDocker min. 20.10.10, containerd min. 1.5.6, docker-compose min. 1.28.0
NetBox manuálna inštaláciaNajčastejšie Ubuntu/Debian LinuxPython min. 3.10; podporované Python verzie sú 3.10, 3.11, 3.12
NetBox na Raspberry PiRaspberry Pi OS / Debian-based LinuxDocker + docker-compose, ideálne Raspberry Pi 4/5, aspoň 2 GB RAM
NetBox na WindowsWindows 10/11 alebo Windows Server cez WSL2/Docker DesktopDocker Desktop + WSL2
NetBox na macOSmacOS cez Docker DesktopDocker Desktop

Odporúčané minimum pre malý lab

ProstriedokMinimumOdporúčané
CPU1 vCPU2 vCPU
RAM2 GB4 GB
Disk10–20 GB30+ GB
OSLinuxUbuntu/Debian/Raspberry Pi OS
Docker20.10.10+aktuálna stabilná verzia
Docker Compose1.28.0+novší docker compose plugin alebo docker-compose

Krátka poznámka

NetBox je najjednoduchšie prevádzkovať cez Docker na Linux serveri. Potrebuje funkčný Docker, Docker Compose, databázu PostgreSQL a Redis/Valkey, ktoré sú pri netbox-docker nasadení súčasťou docker-compose stacku.

Vytvorenie priečinka

mkdir -p ~/netbox
cd ~/netbox

Stiahnutie oficiálneho NetBox Docker repozitára

git clone -b release https://github.com/netbox-community/netbox-docker.git .

Potom skontrolujte obsah priečinka:

ls

Uvidíte niečo takéto

docker-compose.yml
docker-compose.override.yml.example
env
configuration
README.md

Vytvorte override súbor

cp docker-compose.override.yml.example docker-compose.override.yml

Nastavenie portu NetBoxu

Pôvodný port

services:
  netbox:
    ports:
      - "8000:8080"

Ja som ho potreboval zmeniť na 4030

sed -i 's/"8000:8080"/"4030:8080"/' docker-compose.override.yml

a ešte pred „Spustenie kontajneru“. Presne tam sa rieši port 4030, takže tá poznámka tam bude logicky sedieť. Na stránke máš časť „Nastavenie portu NetBoxu“ na riadkoch, kde meníš 8000:8080 na 4030:8080, a hneď potom nasleduje „Spustenie kontajneru“.

## Poznámka k portu 4030 a službe netbox-worker

Pri úprave portu treba dať pozor, aby verejný port `4030` používala iba hlavná služba `netbox`.

V mojom prípade sa po reštarte servera objavila chyba:

    Error response from daemon: failed to set up container networking:
    Bind for 0.0.0.0:4030 failed: port is already allocated

Dôvod bol ten, že v `docker-compose.yml` je použitý YAML anchor:

    netbox: &netbox

a služba `netbox-worker` dedí nastavenia z hlavnej služby `netbox` cez:

    <<: *netbox

Ak hlavná služba `netbox` obsahuje:

    ports:
      - "4030:8080"

tak môže túto časť zdediť aj `netbox-worker`. Potom sa oba kontajnery pokúšajú použiť rovnaký port `4030`.

Riešenie je v časti `netbox-worker` zrušiť dedenie portov:

    netbox-worker:
      <<: *netbox
      ports: []

Po úprave konfigurácie stačí stack reštartovať:

    sudo docker-compose down
    sudo docker-compose up -d

Kontrola:

    sudo docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

Správny stav je, že port `4030` má iba hlavný NetBox kontajner:

    netbox-netbox-1          0.0.0.0:4030->8080/tcp
    netbox-netbox-worker-1   bez verejného portu

Môžeme to skontrolovať

cat docker-compose.override.yml

Spustenie kontajneru

sudo docker-compose up -d

Prvý štart a stav unhealthy

Pri prvom spustení NetBoxu môže kontajner chvíľu svietiť ako:

unhealthy

alebo môže docker-compose up -d skončiť hláškou:

dependency failed to start: container netbox-netbox-1 is unhealthy

Môžeme overiť stav

sudo docker-compose ps

Ak je všetko v poriadku, kontajnery by mali mať stav healthy.

Môžeme sledovať logy

sudo docker-compose logs -f netbox

Treba počkať, kým sa objaví:

✅ Initialisation is done.
[INFO] Listening at: http://:::8080
sudo docker-compose ps

Ak je NetBox stále označený ako unhealthy, ale inicializácia už dobehla, pomôže reštart služby:

sudo docker-compose restart netbox
sudo docker-compose ps

Poznámka

Pri prvom štarte NetBox vykonáva databázové migrácie, preto môže byť kontajner niekoľko minút označený ako unhealthy. Po dokončení migrácií sa stav zmení na healthy.

Prístup k službe

http://IP_ADRESA_SERVERA:4030

Vytvorenie užívateľa

Pred prihlásením je potrebné vytvoriť užívateľa

sudo docker-compose exec netbox /opt/netbox/netbox/manage.py createsuperuser

Skript sa spýta nasledovné veci

Username:
Email address:
Password:
Password again:

Monitoring zmien na slovensko.sk cez changedetection.io, Docker a Ubuntu Server 24.04 LTS na Raspberry pi

Slovensko.sk nemá možnosť posielania mailových notifikácií o nových verziách eID klient a Disig Web signer. Hľadal som nejaký nástroj a našiel som changedetection.io.

Čo je changedetection.io?

changedetection.io je open-source nástroj na monitorovanie zmien na webových stránkach.
Aplikácia v pravidelných intervaloch kontroluje zadané URL adresy a pri zistení zmeny vie používateľa upozorniť napríklad e-mailom, cez webhook, Telegram, Discord alebo iné notifikačné kanály.

V tomto riešení sa changedetection.io používa na sledovanie stránky slovensko.sk/sk/na-stiahnutie, aby bolo možné včas zachytiť vydanie novej verzie softvéru, ako je eID klient, D.Suite/eIDAS alebo D.Launcher.

Inštalácia:

Vytvoríme si priečinok changedetection

mkdir changedetection

Cez textový editor nano, vim, alebo vi vytvoríme textový súbor

nano docker-compose.yml

Do súboru vložíme, napríklad toto. Port samozrejme môžete meniť, len u mňa som musel použiť tento.

services:
  changedetection:
    image: dgtlmoon/changedetection.io
    container_name: changedetection
    restart: unless-stopped
    ports:
      - "4020:5000"
    volumes:
      - ./datastore:/datastore
    environment:
      - PLAYWRIGHT_DRIVER_URL=ws://browserless-chrome:3000
      - BASE_URL=http://10.10.8.4:4020
    depends_on:
      - browserless-chrome

  browserless-chrome:
    image: browserless/chrome
    container_name: browserless-chrome
    restart: unless-stopped
    environment:
      - MAX_CONCURRENT_SESSIONS=5

Spustenie kontajneru

sudo docker compose up -d

Keď sa spustí kontajner tak otvorte webový prehliadač a zadajte IP adresu a port danej služby

X.X.X.X:4020

Ak chceme monitorovať slovensko.sk/sk/na-stiahnutie

Vložíme link a následne Edit > Watch

Následne klikneme na Notifications

Tam zadáme reťazec pre Mailcow, bude vyzerať nejak takto:

mailtos://slovensko-monitor%40ibasterisk.eu:heslo_k_uctu@mail.ibasterisk.eu:587?to=ivan.baronak%40sluzobny.com,ivan.baronak%40ibasterisk.eu&from=slovensko-monitor%40ibasterisk.eu

Tu je dôležité, aby existoval mail v mojom prípade som si vytvoril mailovú schránku slovensko-monitor@ibasterisk.eu a je potrebné zadať heslo k tomuto účtu. Následne som chcel aby mi mailové notifikácie posielalo aj na služobný mail.

Vysvetlivky:

V URL sa znak @ v používateľskom mene radšej kóduje ako: %40

Keď máte napísaný reťazec, môžete otestovať spojenie

Send test notification. Ak budete mať hlášku OK – Send test notification, tak syntax je v poriadku a malo by to prísť na obe mailové adresy.

Potom je potrebné, ako často má sledovať zmeny

A nastaviť prípadne časové pásmo.

Matrix (Synapse) a Element – Raspberry Pi Ubuntu 24.04 server LTS Docker

Funkcie (Čo to dokáže?)

  • End-to-End šifrovanie (E2EE): Tvoje správy sú šifrované priamo v zariadení. Ani ty ako admin servera si ich (teoreticky) neprečítaš v databáze.
  • Federácia: Môj server na IP 10.10.8.5 sa môže (ak to dovolím) prepojiť s ostatnými servermi na svete (napr. matrix.org).
  • Mosty (Bridges): Matrix dokáže pomocou doplnkov prepojiť správy z WhatsAppu, Telegramu alebo Signalu do jednej aplikácie.
  • Multimédiá: Podpora pre prenos súborov, hlasové správy a video hovory (cez Jitsi alebo LiveKit).
  • Synchrónnosť: Môžeš byť prihlásený na mobile, webe aj desktope naraz a všetko sa okamžite synchronizuje.

Minimálne HW požiadavky (Raspberry Pi / Ubuntu)

Matrix (Synapse) je napísaný v Pythone a vie byť celkom „hladný“ na RAM, najmä ak začneš používať federáciu (pripájať sa do veľkých miestností).

KomponentMinimum (1-5 používateľov)Odporúčané (pre plynulý chod)
CPUARMv7 / ARMv8 (RPi 3 a novšie)RPi 4 alebo 5 (4 jadrá)
RAM1 GB (veľmi tesné, treba Swap)2 GB – 4 GB
Disk16 GB MicroSD (Class 10)32 GB+ (ideálne SSD cez USB 3.0)
Sieť100 Mbps (Ethernet)1 Gbps Ethernet

Poznámka

Nakoľko tento manuál vznikol po inštalácií a konfigurácií Matrix Chat, tak sa mi odlišujú IP adresy a porty.

Vytvorenie priečinkov

V kontajneroch vytvoríme nový priečinok napr. chat

mkdir chat

Vytvoríme tomto priečinku chat vytvoríme ďalší priečinok s názvom element

mkdir element

Vytvorenie config.janson

v textovom editore vytvoríme config.janson

nano config.janson

Do neho vložíme, IP adresu, na ktorej chceme aby bežala služba

{
  "default_server_config": {
    "m.homeserver": {
      "base_url": "http://10.10.8.5:8008",
      "server_name": "10.10.8.5"
    }
  }
}

Generovanie počiatočnej konfigurácie Synapse

Pred spustením samotného Compose musíme vygenerovať základné konfiguračné súbory Synapse (homeserver.yaml), inak kontajner nenaštartuje správne.

sudo docker run -it --rm \
  -v $(pwd)/data:/data \
  -e SYNAPSE_SERVER_NAME=10.10.8.5 \
  -e SYNAPSE_REPORT_STATS=no \
  matrixdotorg/synapse:latest generate

Výstup:

sudo docker run -it --rm \
> -v $(pwd)/data:/data \
> -e SYNAPSE_SERVER_NAME=10.10.8.5 \
> -e SYNAPSE_REPORT_STATS=no \
> matrixdotorg/synapse:latest generate
[sudo] password for ivan:
Unable to find image 'matrixdotorg/synapse:latest' locally
latest: Pulling from matrixdotorg/synapse
53196b1f47bd: Pull complete
e7f2a93f0c7a: Pull complete
3c389b3eef21: Pull complete
b08101a833d6: Pull complete
ad999efbff48: Pull complete
6a1e34c16502: Pull complete
2bc10f896e2b: Pull complete
338cdf1f8dc0: Pull complete
ddd420bbfc56: Pull complete
fcc2c9933709: Pull complete
Digest: sha256:9d6bef0a269608d4422bbc5a39140f4a7f667802bcdac143eac0f41f80924dcf
Status: Downloaded newer image for matrixdotorg/synapse:latest
Creating log config /data/10.10.8.5.log.config
Setting ownership on /data to 991:991
Generating config file /data/homeserver.yaml
Generating signing key file /data/10.10.8.5.signing.key
A config file has been generated in '/data/homeserver.yaml' for server name '10.10.8.5'. Please review this file and customise it to your needs.

Vytvorenie docker-compose.yaml

Vytvoríme docker-compose.yaml (ja som to chcel zámerne na porte 4000)

services:
  synapse:
    image: matrixdotorg/synapse:latest
    container_name: synapse
    restart: always
    environment:
      SYNAPSE_SERVER_NAME: "10.10.8.5"
      SYNAPSE_REPORT_STATS: "no"
    volumes:
      - ./data:/data
    ports:
      - "8008:8008"

  element:
    image: vectorim/element-web:latest
    container_name: element
    restart: always
    ports:
      - "4000:80"
    volumes:
      - ./element/config.json:/app/config.json


Spustenie docker compose

Potom spustíme príkazok

sudo docker compose up -d

Môžeme sledovať logy

sudo docker logs -f synapse
sudo docker logs -f element

Teraz môžeme ísť na webovú stránku

http://10.10.8.5:4000/

Vytvorenie užívateľa

Keď všetko prebehne v poriadku, vytvoríme užívateľa idealne prveho, ako admin

sudo docker exec -it synapse register_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml

Nevytvárajú sa účty pomocou GUI, ale len pomocou príkazového riadku

Otvoríme si, chat vo webovom prehliadači a klikneme na Invite už vopred vytvoreného užívateľa

Vypisuje sa to v takomto tvare

Verejný chat

Ak chceme mať chat verejný je potrebné urobiť portforwarding. Je potrebné urobiť 2.

  • Jedno pravidlo na prístup na webové rozhranie u mňa port 3090
  • Druhé, aby sa mohli odosielať správy

Vo fortigate to vyzerá následovne

Potom následne ísť do FireWall Policy

A tu vytvorené pravidla pridať

Potom následne kliknúť na Apply

Potom u poskytovateľa domený je potrebné urobiť A záznam

Upozornenie mobilná aplikácia potrebuje SSL certifikát, inak sa nedokáže pripojiť na server

Podman – Inštalácia WordPress

Začneme s inštaláciou podman

sudo apt update
sudo apt install podman

Ja som rozhodol, že aplikácia bude bežať na porte 3060 a vedel som že budem inštalovať WordPress tak som, ak prvé vytvoril priečinok wordpress

mkdir wordpress

Následne som definoval port

podman pod create --name pod-wp -p 3060:80

Inštalácia databázy

podman run -d --pod pod-wp --name wp-db \
  -e MYSQL_ROOT_PASSWORD=adminheslo \
  -e MYSQL_DATABASE=wordpress \
  -e MYSQL_USER=moto_user \
  -e MYSQL_PASSWORD=moto_heslo \
  -v ./db_data:/var/lib/mysql:Z \
  docker.io/library/mariadb:latest

Inštalácia WordPress

podman run -d --pod pod-wp --name wp-app \
  -e WORDPRESS_DB_HOST=127.0.0.1 \
  -e WORDPRESS_DB_USER=moto_user \
  -e WORDPRESS_DB_PASSWORD=moto_heslo \
  -e WORDPRESS_DB_NAME=wordpress \
  -v ./wp_data:/var/www/html:Z \
  docker.io/library/wordpress:latest

Následne otvortw webový prehliadač v tvare:

http://X.X.X.X:3060

Docker základné príkazy

Spustenie a zastavenie projektov

Vytvorí a spustí všetky kontajnery definované v súbore.

docker compose up

Spustí kontajnery na pozadí (tzv. „detached“ mód), takže môžete ďalej používať terminál.

docker compose up -d

Úplne zastaví a odstráni kontajnery, siete a obrázky definované v súbore. (Dáta vo volume zostanú zachované, ak ich explicitne nezmažeme).

docker compose down

Iba zastaví bežiace kontajnery, ale neodstráni ich.

docker compose stop

Opäť spustí predtým zastavené kontajnery.

docker compose start

Monitorovanie a stav

Zobrazí zoznam kontajnerov patriacich k projektu a ich aktuálny stav (či bežia, alebo spadli).

docker compose ps

Vypíše výstup (logy) zo všetkých služieb.

docker compose logs

Sleduje logy v reálnom čase (veľmi užitočné pri ladení chýb).

docker compose logs -f

Správa zmien a zostavovanie

Zostaví (alebo prebuduje) obrazy (images) podľa inštrukcií v Dockerfile.

docker compose build

Stiahne novšie verzie obrazov z Docker Hubu bez toho, aby hneď reštartoval služby.

docker compose pull

Reštartuje všetky služby (vhodné, ak si zmenil nejakú konfiguráciu v aplikácii, ale nie v samotnom compose súbore).

docker compose restart

Poznámka: Ak používate staršiu verziu Dockera, možno budete musieť písať docker-compose (s pomlčkou). V nových verziách je to už integrované priamo, ako podpríkaz docker compose

Asterisk – Na docker Ubuntu Server 24.04 LTS

Na inštaláciu som zvolil Raspberry pi 5 s Ubuntu Server 24.04 LTS

  • Cieľ: nainštalovať Asterisk 17 s FreePBX 15
  • inštalácia trva približne do 15 minút

Vytvoril som docker-compose.yaml

vim docker-compose.yaml
version: '2'

services:
  freepbx-app:
    container_name: freepbx-app
    image: epandi/asterisk-freepbx-arm:17.15-latest
    ports:
      - 3020:80                # Tvoj požadovaný port 3020
      - 5060:5060/udp
      - 5160:5160/udp
      - 18000-18100:18000-18100/udp
      - 4445:4445              # Flash Operator Panel
    volumes:
      # Použijeme relatívne cesty (.), aby sa ti priečinky vytvorili tam, kde si teraz
      - ./certs:/certs
      - ./data:/data
      - ./logs:/var/log
      - ./www:/var/www/html
      - ./db:/var/lib/mysql
    environment:
      - TZ=Europe/Bratislava
      - RTP_START=18000
      - RTP_FINISH=18100
      - DB_EMBEDDED=TRUE
      - ENABLE_FAIL2BAN=TRUE
    restart: always
    network_mode: "bridge"
    cap_add:
      - NET_ADMIN
    privileged: true

Spustil som docker kontajner

sudo docker-compose up -d

Logy som pozeral

sudo docker logs -f freepbx-app
udo docker logs -f freepbx-app
[s6-init] making user provided files available at /var/run/s6/etc...exited 0.
[s6-init] ensuring user provided files have correct perms...exited 0.
[fix-attrs.d] applying ownership & permissions fixes...
[fix-attrs.d] 00-functions: applying... 
[fix-attrs.d] 00-functions: exited 0.
[fix-attrs.d] 01-s6: applying... 
[fix-attrs.d] 01-s6: exited 0.
[fix-attrs.d] 02-zabbix: applying... 
[fix-attrs.d] 02-zabbix: exited 0.
[fix-attrs.d] 03-logrotate: applying... 
[fix-attrs.d] 03-logrotate: exited 0.
[fix-attrs.d] done.
[cont-init.d] executing container initialization scripts...
[cont-init.d] 00-startup: executing... 
[cont-init.d] 00-startup: exited 0.
[cont-init.d] 01-timezone: executing... 
[cont-init.d] 01-timezone: exited 0.
[cont-init.d] 02-permissions: executing... 
[cont-init.d] 02-permissions: exited 0.
[cont-init.d] 03-zabbix: executing... 
[cont-init.d] 03-zabbix: exited 0.
[cont-init.d] 04-cron: executing... 
[cont-init.d] 04-cron: exited 0.
[cont-init.d] 05-fail2ban: executing... 
[INFO] ** [fail2ban] Starting Fail2ban
[cont-init.d] 05-fail2ban: exited 0.
[cont-init.d] 05-smtp: executing... 
[NOTICE] ** [smtp] Disabling SMTP Features
[cont-init.d] 05-smtp: exited 0.
[cont-init.d] 08-mongodb: executing... 
[cont-init.d] 08-mongodb: exited 0.
[cont-init.d] 09-mariadb: executing... 
[INFO] ** [mariadb] New embedded database detected, setting up..
[cont-init.d] 09-mariadb: exited 0.
[cont-init.d] 10-freepbx: executing... 
[NOTICE] ** [freepbx] Creating default configuration files
[NOTICE] ** [freepbx] Setting file permissions
[INFO] ** [freepbx] New install detected - please wait while we fetch FreePBX - will take up to 30 minutes!
[NOTICE] ** [freepbx] Starting Asterisk 17.9.3 for the first time
[NOTICE] ** [freepbx] Installing FreePBX 15.0.16.56 source code (db embedded)
[NOTICE] ** [freepbx] Enabling default modules:
[NOTICE] ** [freepbx] - framework, core
[NOTICE] ** [freepbx] - cdr (embedded db)
[NOTICE] ** [freepbx] - backup, callrecording, conferences, dashboard, featurecodeadmin, filestore, fw_langpacks, infoservices, languages, logfiles, music, recordings, sipsettings, soundlang, voicemail
[NOTICE] ** [freepbx] - certman, userman, pm2
[NOTICE] ** [freepbx] - ucp
[INFO] ** [freepbx] Finished installation of FreePBX modules - proceeding with next phase of install
[NOTICE] ** [freepbx] Setting RTP ports - start: '18000' finish: '18100'
[INFO] ** [freepbx] Starting Asterisk 17.9.3
[NOTICE] ** [freepbx] Enabling SSL
[WARN] ** [freepbx] No SSL certs found, autogenerating self-signed - WebRTC will not work with a self-signed certificate!
[INFO] ** [freepbx] Web server started - container initialization completed - visit your http(s)://.../admin to administer
[cont-init.d] 10-freepbx: exited 0.
[cont-init.d] 15-socat: executing... 
[cont-init.d] 15-socat: exited 0.
[cont-init.d] 99-container: executing... 
[cont-init.d] 99-container: exited 0.
[cont-init.d] done.
[services.d] starting services
[services.d] done.
[INFO] ** [zabbix] Starting Zabbix Agent
[INFO] ** [cron] Starting cron

Keď to zbehlo

Systém si vytváral priečinky

asterisk$ ls
certs  data  db  docker-compose.yaml  logs  www

Bolo potrebné sa prihlásiť

http://10.10.8.5:3020/admin

Zvolil som potrebné údaje na vytvorenie admina

Vytvorenie Docker MP3 prehrávača online

Môj syn, má rad niekoľko playlistov, ktoré rád počúva pri uspávaní. Tak som sa rozhodol, nepoužívať youtube, ale vyskúšam urobiť vlastný MP3 prehrávač, ktorý by fungoval online. Zvolil so na to Docker a zadanie bolo následovné:

  • Sprístupniť niekoľko playlistov
  • pozadie, aby sa menilo každých 5 minút
  • playlisty, aby sa dali meniť
  • Hudba aby sa dala stišovať, zosiľňovať
  • Playlist, aby sa dal zastaviť a znova spustiť.
  • Chcel som, aby docker bežal na porte 3030

Postup:

Vytvoril som jeden priečinok pomenovaný matej.

Do neho som vložil 2 priečinky

  • MP3
  • JPG

Do jpg som nahodil obrázky a do MP3 playlisty, ktoré chcem aby sa dali spúšťať.

Vytvoril som súbory:

  • docker-compose.yaml
  • index.html
  • script.js
  • style.css

docker-compose.yaml

version: '3'
services:
  mato-player:
    image: nginx:alpine
    container_name: mato_container
    ports:
      - "3030:80"
    volumes:
      - ./mato:/usr/share/nginx/html
    restart: always

index.html

<!DOCTYPE html>
<html lang="sk">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mato Player</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>🎵 Maťkov playlist</h1>

        <div class="controls-group">
            <label for="music-select">Vyber si zvuk/skladbu:</label>
            <select id="music-select">
                <option value="mp3/Brahms.mp3">Brahms - Uspávanka</option>
                <option value="mp3/mozart.mp3">Mozart - Klasika</option>
                <option value="mp3/voda.mp3">Šum vody</option>
                <option value="mp3/metal.mp3">Metal</option>
                <option value="mp3/vysavac.mp3">Biely šum (Vysávač)</option>
            </select>
        </div>

        <button id="music-btn" class="btn-paused" onclick="toggleMusic()">🎶 Spustiť</button>

        <div class="volume-container">
            <label for="volume-control">Hlasitosť</label>
            <input type="range" id="volume-control" min="0" max="1" step="0.1" value="0.5">
        </div>
    </div>

    <audio id="bg-music" loop>
        <source src="mp3/Brahms.mp3" type="audio/mpeg">
    </audio>

    <script src="script.js"></script>
</body>
</html>

script.js

document.addEventListener('DOMContentLoaded', () => {
    const audio = document.getElementById("bg-music");
    const volumeControl = document.getElementById("volume-control");
    const musicSelect = document.getElementById("music-select");
    const musicBtn = document.getElementById("music-btn");

    // --- 1. ROTÁCIA OBRÁZKOV (každých 5 minút) ---
    const images = [
        'astrobot.jpg', 'astrobot2.jpg', 'gumkaci.jpg', 'gumkaci2.jpg',
        'hlada_sa_nemo.jpg', 'macko_pu.jpg', 'paw_patrol.jpg', 
        'paw-patrol2.jpg', 'smolkovia.jpg'
    ];
    
    let currentImgIndex = Math.floor(Math.random() * images.length);

    const changeBg = () => {
        const imgName = images[currentImgIndex];
        document.body.style.backgroundImage = `url('jpg/${imgName}')`;
        console.log("Pozadie zmenené na: " + imgName);
        currentImgIndex = (currentImgIndex + 1) % images.length;
    };

    changeBg(); // Spustiť hneď
    setInterval(changeBg, 300000); // 300 000 ms = 5 minút


    // --- 2. OVLÁDANIE HUDBY ---
    if (audio && volumeControl) {
        audio.volume = 0.5;
        volumeControl.addEventListener('input', (e) => {
            audio.volume = e.target.value;
        });
    }

    if (musicSelect && audio) {
        musicSelect.addEventListener('change', () => {
            const isPlaying = !audio.paused;
            audio.src = musicSelect.value;
            if (isPlaying) {
                audio.play().catch(e => console.log("Čakám na interakciu..."));
            }
            // Reset tlačidla ak sa zmení skladba počas pauzy
            if (audio.paused) {
                musicBtn.innerText = "🎶 Spustiť: " + musicSelect.options[musicSelect.selectedIndex].text;
            }
        });
    }
});

function toggleMusic() {
    const audio = document.getElementById("bg-music");
    const btn = document.getElementById("music-btn");

    if (audio.paused) {
        audio.play().then(() => {
            btn.innerText = "⏸ Pozastaviť";
            btn.className = "btn-playing";
        }).catch(err => alert("Najprv kliknite niekde na stránku pre povolenie zvuku."));
    } else {
        audio.pause();
        btn.innerText = "🎶 Pokračovať";
        btn.className = "btn-paused";
    }
}

style.css

body {
    margin: 0;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    font-family: 'Arial', sans-serif;
    background-size: cover;
    background-position: center;
    transition: background-image 1.5s ease-in-out; /* Plynulá zmena obrázka */
}

.container {
    background: rgba(0, 0, 0, 0.6);
    padding: 30px;
    border-radius: 20px;
    color: white;
    text-align: center;
    width: 300px;
    backdrop-filter: blur(5px);
    border: 2px solid rgba(255, 255, 255, 0.2);
}

.controls-group { margin: 20px 0; }

select {
    width: 100%;
    padding: 10px;
    border-radius: 10px;
    background: #444;
    color: white;
    border: none;
}

#music-btn {
    width: 100%;
    padding: 15px;
    border-radius: 10px;
    border: none;
    font-weight: bold;
    cursor: pointer;
    color: white;
    font-size: 1rem;
}

.btn-paused { background-color: #d62828; }
.btn-playing { background-color: #28a745; }

.volume-container { margin-top: 20px; }

input[type="range"] { width: 100%; cursor: pointer; }

Spustil som docker

sudo docker-compose up -d

Prípadne, ak je potrebné urobiť zmeny tak je nutné docker zastaviť a znovu spustiť

sudo docker-compose down
sudo docker-compose up -d

Docker aplikácia – odpočet dní a hodín do ďalších Vianoc + zmena časového pásma

Som robil svoju prvú vlastnú webovú aplikáciu určenú, pre odpočet dní a hodín do ďalších Vianoc. Áno, inšpirovala vianočná nálada mojej ženy.

Vymyslel som si zadanie:

  • Nastaviť 5 pozadí, ktoré sa budú meniť po 10 minútach
  • V pozadí bude hrať vianočná hudba – (Viac playlistov)
  • Bude tam možnosť si zvoliť časové pásmo
  • Zvoliť si prepočet na dni a hodiny
  • Bude možné hudbu zastaviť, stíšiť, znovu spustiť
  • Tlačidlo bude buď zelené -(Hudba hrá)
  • Tlačidlo bude červené – (hudba nehrá)
  • Vyvorenei favicon

Vytvoril som priečinok

mdkir christmas-countdown

Do priečinka som vytvoril textové súbory

  • Dockerfile
  • docker-compose.yaml
  • index.html
  • script.js
  • style.css
  • citaj

A zložky, do ktorých som vložil obrázky a hudbu

  • jpg som pomenoval: christmas1.jpg, christmas2.jpg, christmas3.jpg, christmas4.jpg, christmas5.jpg
  • mp3 som urobil niekoľko hodinový súbor a pomenoval christmas01.mp3.
  • favicon uložil som favicon.png

Ďalej do vytvorených súborov som napísal kódy prostredníctvom buď vim, alebo nano:

Dockerfile

FROM nginx:alpine
# Skopíruj všetky súbory do Nginxu
COPY . /usr/share/nginx/html/
# Tento riadok zabezpečí, že Nginx bude posielať správne hlavičky pre JS
RUN sed -i '/types {/a \    application/javascript js;' /etc/nginx/nginx.conf

docker-compose.yaml

services:
  web:
    image: nginx:alpine
    ports:
      - "3010:80"  # port Vianoce
    volumes:
      - /home/ivan/christmas-countdown:/usr/share/nginx/html:ro
    restart: always

script.js



document.addEventListener('DOMContentLoaded', () => {
console.log("Vianočný web: Plná verzia so všetkými funkciami.");
// --- ELEMENTY ---
const timerDisplay = document.getElementById('timer');
const musicBtn = document.getElementById('music-btn');
const audio = document.getElementById('bg-music');
const playlistSelect = document.getElementById('playlist-select');
const volumeSlider = document.getElementById('volume-slider');
const btnDays = document.getElementById('btn-days');
const btnHours = document.getElementById('btn-hours');
const timezoneSelect = document.getElementById('timezone-select');

// --- 1. NÁHODNÉ POZADIE ---
const backgrounds = ['jpg/christmas1.jpg', 'jpg/christmas2.jpg', 'jpg/christmas3.jpg', 'jpg/christmas4.jpg', 'jpg/christmas5.jpg'];
document.body.style.backgroundImage = `url('${backgrounds[Math.floor(Math.random() * backgrounds.length)]}')`;

// --- 2. HUDBA A PLAYLISTY ---
const updateButtonUI = () => {
    if (!musicBtn) return;
    if (audio.paused) {
        musicBtn.innerText = "🎶 ZAPNÚŤ HUDBU";
        musicBtn.style.setProperty('background-color', '#ff4d4d', 'important');
    } else {
        musicBtn.innerText = "⏸ POZASTAVIŤ";
        musicBtn.style.setProperty('background-color', '#28a745', 'important');
    }
};

// Obsluha tlačidla Play/Pause
musicBtn.addEventListener('click', () => {
    if (!audio.src || audio.src.endsWith('/')) {
        audio.src = playlistSelect.value;
    }
    if (audio.paused) {
        audio.play().then(updateButtonUI).catch(() => alert("Klikni najprv na plochu!"));
    } else {
        audio.pause();
        updateButtonUI();
    }
});

// OPRAVA PREKLIKÁVANIA PLAYLISTOV
playlistSelect.addEventListener('change', () => {
    const wasPlaying = !audio.paused;
    audio.src = playlistSelect.value;
    audio.load();
    if (wasPlaying) {
        audio.play().then(updateButtonUI);
    } else {
        updateButtonUI();
    }
});

// Hlasitosť
if (volumeSlider) {
    audio.volume = volumeSlider.value;
    volumeSlider.addEventListener('input', (e) => {
        audio.volume = e.target.value;
    });
}

// --- 3. ODPOČET A ČASOVÉ PÁSMA ---
let viewMode = 'days'; 

const updateCountdown = () => {
    if (!timerDisplay) return;

    // Funkčné časové pásmo
    const tz = timezoneSelect ? timezoneSelect.value : "Europe/Bratislava";
    const now = new Date(new Date().toLocaleString("en-US", {timeZone: tz}));

    let target = new Date(now.getFullYear(), 11, 24, 0, 0, 0);
    if (now > target) target.setFullYear(target.getFullYear() + 1);

    const diff = target - now;

    if (viewMode === 'days') {
        const d = Math.floor(diff / 86400000);
        const h = Math.floor((diff / 3600000) % 24);
        const m = Math.floor((diff / 60000) % 60);
        const s = Math.floor((diff / 1000) % 60);
        timerDisplay.innerText = `${d}d ${h}h ${m}m ${s}s`;
    } else {
        const hTotal = Math.floor(diff / 3600000);
        const m = Math.floor((diff / 60000) % 60);
        const s = Math.floor((diff / 1000) % 60);
        timerDisplay.innerText = `${hTotal.toLocaleString()}h ${m}m ${s}s`;
    }
};

if (timezoneSelect) timezoneSelect.addEventListener('change', updateCountdown);

btnDays.addEventListener('click', () => {
    viewMode = 'days';
    btnDays.classList.add('active');
    btnHours.classList.remove('active');
    updateCountdown();
});
btnHours.addEventListener('click', () => {
    viewMode = 'hours';
    btnHours.classList.add('active');
    btnDays.classList.remove('active');
    updateCountdown();
});

setInterval(updateCountdown, 1000);
updateCountdown();

// --- 4. SNEŽENIE ---
setInterval(() => {
    const snow = document.createElement('div');
    snow.className = 'snowflake';
    snow.innerHTML = '❄';
    snow.style.left = Math.random() * 100 + 'vw';
    snow.style.animation = `fall ${Math.random() * 3 + 2}s linear forwards`;
    document.body.appendChild(snow);
    setTimeout(() => snow.remove(), 5000);
}, 200);
});

index.html

<!DOCTYPE html>
<html lang="sk">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vianočný Odpočet — ibasterisk.eu</title>
    <link rel="stylesheet" href="style.css">
    <link rel="icon" type="image/png" href="favicon/favicon.png">
</head>
<body>
    <div id="snow-container"></div>

    <div class="container">
        <h1>🎅 Vianočný Odpočet</h1>

        <div id="countdown">
            <span id="timer">Načítavam...</span>
        </div>

        <div class="view-toggle">
            <button id="btn-days" class="active">Dni</button>
            <button id="btn-hours">Hodiny</button>
        </div>

        <div class="controls-group">
            <label>Časové pásmo:</label>
            <select id="timezone-select">
                <option value="Europe/Bratislava">🇸🇰 Slovensko</option>
                <option value="Asia/Tokyo">🇯🇵 Tokio (Japonsko)</option>
                <option value="Europe/Moscow">🇷🇺 Moskva (Rusko)</option>
                <option value="Australia/Sydney">🇦🇺 Sydney (Austrália)</option>
            </select>
        </div>

        <div class="controls-group">
            <label>Vyber Playlist:</label>
            <select id="playlist-select">
                <option value="mp3/christmas01.mp3">Vianočný Mix 01</option>
                <option value="mp3/buble1.mp3">Michael Bublé 1</option>
                <option value="mp3/buble2.mp3">Michael Bublé 2</option>
                <option value="mp3/top20.mp3">Vianočná Top 20</option>
            </select>
        </div>

        <button id="music-btn" class="btn-stopped">🎶 Zapnúť hudbu</button>

        <div class="volume-container">
            <label>Hlasitosť</label>
            <input type="range" id="volume-slider" min="0" max="1" step="0.1" value="0.5">
        </div>

        <audio id="bg-music" loop></audio>
    </div>

    <script src="script.js"></script>
</body>
</html>

style.css

body {
    margin: 0; padding: 0;
    width: 100vw; height: 100vh;
    display: flex; justify-content: center; align-items: center;
    background-size: cover; background-position: center;
    background-color: #1a1a1a;
    font-family: 'Segoe UI', Arial, sans-serif;
    transition: background-image 2s ease-in-out;
    overflow: hidden;
}

.container {
    background: rgba(0, 0, 0, 0.8);
    backdrop-filter: blur(10px);
    padding: 30px; border-radius: 25px;
    color: white; text-align: center; width: 350px;
    position: relative; z-index: 10;
    box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}

#timer {
    font-size: 2rem; font-weight: bold; color: #ff4d4d;
    display: block; margin: 20px 0;
}

.view-toggle { display: flex; justify-content: center; margin-bottom: 20px; }
.view-toggle button {
    background: #444; color: white; border: none;
    padding: 10px 20px; cursor: pointer; transition: 0.3s;
}
.view-toggle button.active { background: #ff4d4d !important; }
.view-toggle button:first-child { border-radius: 10px 0 0 10px; }
.view-toggle button:last-child { border-radius: 0 10px 10px 0; }

select {
    width: 100%; padding: 12px; border-radius: 10px;
    background: #222; color: white; margin-bottom: 15px; border: 1px solid #444;
}

#music-btn {
    width: 100%; padding: 15px; border-radius: 15px;
    border: none; color: white; font-weight: bold;
    cursor: pointer; text-transform: uppercase;
}

.btn-stopped { background-color: #ff4d4d !important; }
.btn-playing { background-color: #28a745 !important; }

.snowflake {
    position: fixed; top: -10px; color: white !important;
    z-index: 1000; pointer-events: none;
    animation: fall linear forwards;
}

@keyframes fall {
    to { transform: translateY(105vh); }
}

.volume-container input { width: 100%; accent-color: #ff4d4d; margin-top: 10px; 
}

citaj

Tento súbor, nieje dôležitý na koľko sú to len moje poznámky

Následne som spustil kontajner

sudo docker-compose down
sudo docker-compose up --build -d

Docker Kibana na Ubuntu 24.04

Kibana je open-source vizualizačný nástroj pre Elasticsearch, ktorý umožňuje prehliadať, analyzovať a vizualizovať dáta pomocou dashboardov, grafov a máp. Je súčasťou Elastic Stack (ELK stack).

Podporované OSLinux (Ubuntu, Debian, CentOS, RHEL), Windows, macOS
Podpora DockerÁno, Kibana má oficiálny Docker image, ktorý umožňuje jednoduché spustenie a škálovanie.
Odporúčané HW požiadavkyCPU: 2 jadrá alebo viac
RAM: minimálne 4 GB (8 GB pre väčšie nasadenia)
Disk: SSD s dostatočnou kapacitou pre logy a indexy
Sieť: stabilné pripojenie k Elasticsearch

Aktualizácia OS

sudo apt update
sudo apt upgrade -y

Inštalácia potrebných závislostí

sudo apt install -y ca-certificates curl gnupg lsb-release

Pridanie Docker GPG kľúča

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Pridanie Docker Repozitára

echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Inštalácia Docker Engine a Docker compose

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Vytvorenie docker-compose.yml

nano docker-compose.yml
version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.11.1
    container_name: elasticsearch
    environment:
      - node.name=elasticsearch
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - es_data:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
    networks:
      - elk

  kibana:
    image: docker.elastic.co/kibana/kibana:8.11.1
    container_name: kibana
    environment:
      ELASTICSEARCH_HOSTS: "http://elasticsearch:9200"
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    networks:
      - elk

volumes:
  es_data:
    driver: local

networks:
  elk:
    driver: bridge

Spustenie docker kontajnerov

sudo docker compose up -d

Otvorte webový prehliadač

http://localhost:5601

Enrollment Token získame

sudo docker exec -it elasticsearch bin/elasticsearch-create-enrollment-token -s kibana

Príklad

 sudo docker exec -it elasticsearch bin/elasticsearch-create-enrollment-token -s kibana
WARNING: Owner of file [/usr/share/elasticsearch/config/users] used to be [root], but now is [elasticsearc     h]
WARNING: Owner of file [/usr/share/elasticsearch/config/users_roles] used to be [root], but now is [elasti     csearch]

eyJ2ZXIiOiI4LjExLjEiLCJhZHIiOlsiMTcyLjE4LjAuMjo5MjAwIl0sImZnciI6IjhmYWEzYjlmZmJjMGQ4MGFjMzM1ZGEzZjM4MmFkYW     VhNzg5NmUxYmUyYWZkNzQzZDNhMzJkYjMyNTY0YTZiNGYiLCJrZXkiOiJWY3lHUnBzQjJ3d1RWZWRxZXJBNzp1TWllMmZoQlM5dUc3Vy1n     Um1SLVJBIn0=

Tento token sa vygeneruje len raz a má časové obmedzenie.

Po jeho vložení do Kibany sa dokončí prvotná konfigurácia.

verifikačný kód nájdeme

sudo docker exec -it kibana bin/kibana-verification-code

A necháme ho zbehnúť

Docker Grafana a Zabbix

Grafana je open-source softvérový nástroj určený na monitorovanie, vizualizáciu a analýzu dát. Slúži na vytváranie prehľadných a interaktívnych dashboardov, ktoré zobrazujú metriky a údaje získané z rôznych dátových zdrojov v reálnom čase. Grafana je využívaná najmä pri monitorovaní systémov, aplikácií, sietí a infraštruktúry.

Aplikácia podporuje inštaláciu na viacerých Linuxových distribúciách a je dostupná aj ako Docker kontajner, čo umožňuje flexibilné nasadenie v rôznych prostrediach.

Podporované platformy a distribúcie

Platforma
Ubuntu
Debian
CentOS / RHEL
Rocky Linux
AlmaLinux
Fedora
openSUSE
Arch Linux
Docker (kontajnerové prostredie)

Hardvérové a systémové požiadavky

ParameterMinimálne požiadavkyOdporúčané hodnoty
CPU1 jadro2 a viac jadier
RAM512 MB1–2 GB a viac
Diskový priestor~200 MBPodľa objemu dát
Sieťové pripojenieZákladné pripojenieStabilné pripojenie
Operačný systémLinux (64-bit)Linux (64-bit)

Inštalácia docker-compose

sudo apt update
sudo apt install -y docker.io docker-compose
sudo systemctl enable --now docker

Vytvoríme priečinok Grafana

mkdir ~/grafana
cd ~/grafana

Vytvoríme docker-compose-grafana.yml

nano docker-compose-grafana.yml

Vložíme do súboru

version: "3.9"

services:
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_USER: admin
      GF_SECURITY_ADMIN_PASSWORD: admin

Spustíme kontajner

sudo docker-compose -f docker-compose-grafana.yml up -d

Inštalácia Zabbix

mkdir ~/zabbix
cd ~/zabbix
nano docker-compose-zabbix.yml
version: '3.5'

services:
  mariadb:
    image: mariadb:11.2
    container_name: zabbix-mariadb
    restart: always
    environment:
      MYSQL_DATABASE: zabbix
      MYSQL_USER: zabbix
      MYSQL_PASSWORD: zabbixpass
      MYSQL_ROOT_PASSWORD: rootpass
      TZ: Europe/Bratislava
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_bin
    volumes:
      - db_data:/var/lib/mysql

  zabbix-server:
    image: zabbix/zabbix-server-mysql:latest
    container_name: zabbix-server
    restart: always
    environment:
      DB_SERVER_HOST: mariadb
      MYSQL_DATABASE: zabbix
      MYSQL_USER: zabbix
      MYSQL_PASSWORD: zabbixpass
      ZBX_TIMEZONE: Europe/Bratislava
    ports:
      - "10051:10051"
    depends_on:
      - mariadb

  zabbix-web:
    image: zabbix/zabbix-web-nginx-mysql:latest
    container_name: zabbix-web
    restart: always
    environment:
      DB_SERVER_HOST: mariadb
      MYSQL_DATABASE: zabbix
      MYSQL_USER: zabbix
      MYSQL_PASSWORD: zabbixpass
      ZBX_SERVER_HOST: zabbix-server
      ZBX_SERVER_PORT: 10051
      TZ: Europe/Bratislava
    ports:
      - "8080:8080"

volumes:
  db_data:

Spustíme kontajner

sudo docker-compose -f docker-compose-zabbix.yml up -d

Prihlásenie na Zabbix

Web: http://<IP_SERVERA>:8080
Default login: Admin / zabbix

Update Zabbix

Stiahnutie novej verzie

cd ~/zabbix
sudo docker-compose -f docker-compose-zabbix.yml pull
sudo docker-compose -f docker-compose-zabbix.yml down

spustenie kontajneru
sudo docker-compose -f docker-compose-zabbix.yml up -d
sudo docker-compose -f docker-compose-zabbix.yml ps

Kontrola po aktualalizácií

sudo docker-compose -f docker-compose-zabbix.yml logs --tail=50

Prihlásenie na Grafana

Vytvoríte si heslo a následne meno je: Admin/admin potom Vás systém vyzve, aby si heslo zmenili a následne sa ním prihlásite

Kubernetes Ubuntu 24.04 Wiki.JS a WordPress

sudo apt udpate
sudo apt upgrade

Nainštalujte K3s

curl -sfL https://get.k3s.io | sh -

Môžete skontrolovať stav nodov

sudo kubectl get nodes

Výstup:

NAME   STATUS   ROLES                  AGE   VERSION
ivan   Ready    control-plane,master   5s    v1.33.5+k3s1

Konfigurácia kubectl (aby si ho mohol používať bez sudo):

mkdir -p $HOME/.kube
sudo cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Nasadenie Wiki.js

Vytvoríme yaml

nano wikijs.yaml

Skpírujeme do neho

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wikijs-data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wikijs
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wikijs
  template:
    metadata:
      labels:
        app: wikijs
    spec:
      containers:
      - name: wikijs
        image: requarks/wiki:latest
        env:
        - name: DB_TYPE
          value: "sqlite"
        - name: DB_FILE
          value: "/data/database.sqlite"
        ports:
        - containerPort: 3000
        volumeMounts:
        - name: data
          mountPath: /data
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: wikijs-data
---
apiVersion: v1
kind: Service
metadata:
  name: wikijs-service
spec:
  type: NodePort
  selector:
    app: wikijs
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
      nodePort: 30080

Následne uložíme

Nasadíme Wiki.js

sudo kubectl apply -f wikijs.yaml
sudo kubectl get pods
sudo kubectl get svc

Teraz otvorte webpvý prehliadač a zadajte IP adresu daného servera v tvare:

http://X.X.X.X:30080

Nasadenie WordPress

Vytvoríme yaml

nano wordpress.yaml

Skopírujeme do neho:

# PersistentVolumeClaim pre MariaDB
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mariadb-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
# PersistentVolumeClaim pre WordPress
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wordpress-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
# MariaDB Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mariadb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mariadb
  template:
    metadata:
      labels:
        app: mariadb
    spec:
      containers:
      - name: mariadb
        image: mariadb:10.11
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "rootpass"
        - name: MYSQL_DATABASE
          value: "wordpress"
        - name: MYSQL_USER
          value: "wpuser"
        - name: MYSQL_PASSWORD
          value: "wppass"
        volumeMounts:
        - name: mariadb-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mariadb-storage
        persistentVolumeClaim:
          claimName: mariadb-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: mariadb
spec:
  selector:
    app: mariadb
  ports:
    - protocol: TCP
      port: 3306
---
# WordPress Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
      - name: wordpress
        image: wordpress:6.6-php8.2-apache
        env:
        - name: WORDPRESS_DB_HOST
          value: mariadb
        - name: WORDPRESS_DB_NAME
          value: wordpress
        - name: WORDPRESS_DB_USER
          value: wpuser
        - name: WORDPRESS_DB_PASSWORD
          value: wppass
        ports:
        - containerPort: 80
        volumeMounts:
        - name: wordpress-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-storage
        persistentVolumeClaim:
          claimName: wordpress-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: wordpress-service
spec:
  type: NodePort
  selector:
    app: wordpress
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30081

Spustenie WordPress

kubectl apply -f wordpress.yaml
kubectl get pods
kubectl get svc

Zadáme IP adresu s portom v tvare:

http://X.X.X.X:30081

Wazuh – Docker Ubuntu 24.04 LTS

Wazuh je open-source bezpečnostný systém na detekciu hrozieb a monitorovanie integrity, ktorý umožňuje zber, analýzu a vizualizáciu bezpečnostných udalostí z počítačov a serverov v reálnom čase.

Pomáha sledovať bezpečnosť a dodržiavanie predpisov, odhaľovať neautorizované zmeny v súboroch, monitorovať sieťovú aktivitu a generovať alarmy pri podozrivej činnosti. Wazuh využíva centralizovaný manažér (Manager), indexovanie logov (OpenSearch) a webový dashboard na prehľadné zobrazovanie alertov.

Používa sa na:

  • Monitorovanie integrity súborov a systémov
  • Detekciu bezpečnostných hrozieb
  • Analýzu logov z rôznych zariadení
  • Audit a dodržiavanie bezpečnostných štandardov (napr. GDPR, PCI-DSS)
  • Centrálne spravovanie a vizualizáciu bezpečnostných udalostí

Hardvérové požiadavky pre Wazuh Single-Node (Docker)

KomponentMinimálneOdporúčané
RAM4 GB8 GB alebo viac
CPU2 jadrá4 jadrá alebo viac
Disk20 GB50 GB alebo viac, SSD odporúčané
Sieť1 Gbps LAN1 Gbps alebo vyššia
OSUbuntu 24.04 LTSUbuntu 24.04 LTS alebo 22.04 LTS

Požiadavky na Docker

  • Docker Engine: ≥ 20.x
  • Docker Compose: ≥ 1.29 (alebo docker compose plugin v novších verziách)
  • Docker musí mať dostatočné práva (odporúčané spúšťať cez sudo alebo pridanie používateľa do skupiny docker)

Požiadavky na disk a úložisko

  • Každý Wazuh manager/agent ukladá logy a alerty:
    • Manager + Indexer môžu rýchlo narásť s počtom monitorovaných hostov.
  • Odporúča sa SSD disk pre rýchlejšie vyhľadávanie a indexovanie v OpenSearch.
  • Odporúčané miesto na Docker volumes: /var/lib/docker/volumes alebo externé úložisko ≥ 50 GB pri strednej infraštruktúre.

Sieťové požiadavky

PortPoužitie
1514 TCP/UDPAgent → Manager (logy)
1515 TCPAgent → Manager (registrácia)
443 TCPWazuh Dashboard HTTPS
9200 TCPWazuh Indexer / OpenSearch

Inštalácia

Urobte update a upgrade

sudo apt update && sudo apt upgrade -y

Nainštalujte vyžadované balíčky

sudo apt install -y git curl apt-transport-https ca-certificates gnupg lsb-release

Nainštzalujte Docker Compose

sudo apt install -y docker.io docker-compose

Povoľtemu, aby sa spúšťal pri boote OS

sudo systemctl enable --now docker

(Voliteľné) povoľte používateľovi spúšťať Docker bez príkazu sudo:

sudo usermod -aG docker $USER

Klonovať Docker Repository Wazuh

cd ~
git clone https://github.com/wazuh/wazuh-docker.git -b v4.14.1
cd wazuh-docker/single-node

Generovanie certifikátov TLS

sudo docker-compose -f generate-indexer-certs.yml run --rm generator

Spustite Wazuh

sudo docker-compose up -d

Otvorte webový prehliadač, a zadajte IP adresu servera na kotrom beží Wazuh

https://X.X.X.X

Defaultné prihlásenie je:

Username: admin
Password: SecretPassword

Úspešné prihlásenie

NextCloud – Docker Ubuntu 24.04 TLS

Nextcloud je cloudové riešenie na ukladanie, zdieľanie a spravovanie súborov.
Umožňuje bezpečný prístup k dokumentom, fotkám, videám a ďalším súborom z ľubovoľného zariadenia s internetom.
Okrem toho podporuje spoluprácu v reálnom čase – editovanie dokumentov, videohovory, chat či kalendáre.
Nextcloud je open-source, takže máte plnú kontrolu nad svojimi dátami a ich bezpečnosťou.
Jednoducho povedané: je to váš vlastný, súkromný cloud, ktorý nahrádza externé služby ako Google Drive alebo Dropbox, s dôrazom na súkromie a flexibilitu.

KomponentMinimálne požiadavky
OS (operačný systém)Linux (napr. Ubuntu 20.04/22.04/24.04), Windows Server, macOS
Webový serverApache ≥ 2.4 alebo Nginx ≥ 1.10
PHPVerzia 8.1 alebo vyššia, s nasledujúcimi rozšíreniami: gd, curl, mbstring, xml, zip, intl, bcmath, gmp, fileinfo, ctype
DatabázaMySQL/MariaDB ≥ 10.5, PostgreSQL ≥ 12, SQLite (len pre testovanie)
RAMMinimálne 512 MB (1 GB odporúčané, viac pre veľké inštalácie)
Diskový priestorMinimálne 500 MB pre inštaláciu + priestor pre súbory používateľov
Pripojenie na internetPožadované pre aktualizácie, doplnky a synchronizáciu
Docker (ak používať)Docker Engine ≥ 20 a Docker Compose ≥ 2.0

Podpora súbor a formátov

TypPodporaPoznámky
VideoMP4, WebM, OggPre iné formáty treba doplnky alebo externé prehrávače
Audio / HudbaMP3, Ogg, WAVPrehráva sa priamo v prehliadači, podpora playlistov cez Nextcloud Music
ObrázkyJPG, PNG, GIF, SVGMiniatury a náhľady sa generujú automaticky
DokumentyPDF, DOCX, ODT, XLSXPre editáciu v reálnom čase: Collabora Online alebo OnlyOffice
Videohovory (integrované)Nextcloud TalkPlne integrované, vhodné pre menšie skupiny
Videohovory (externé)Jitsi MeetMožno integrovať cez externý server alebo iframe, zvláda väčšie skupiny a pokročilé funkcie
Doplnky / externé úložiskáYouTube, Dropbox, Google DriveIntegrácia multimédií a súborov z externých služieb

Inštalácia

Urobte update

sudo apt update && sudo apt upgrade -y

Nainštalujte Docker a Docker Compose

sudo apt install -y docker.io
sudo systemctl enable --now docker
sudo usermod -aG docker $USER

Ak chcete, aby sa Docker a vaše kontajnery spúšťali automaticky po reštarte servera,

sudo systemctl enable docker
sudo systemctl start docker

Nainštalujte Docker Compose

sudo apt install -y docker-compose

Vytvorenie súboru Docker Compose pre Nextcloud

mkdir ~/nextcloud && cd ~/nextcloud

Vytvorte súbor docker-compose.yml

nano docker-compose.yml

Do neho skopírujte:

version: '3'

services:
  db:
    image: mariadb:11
    container_name: nextcloud_db
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
      MYSQL_PASSWORD: your_password
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
    volumes:
      - db_data:/var/lib/mysql

  app:
    image: nextcloud:latest
    container_name: nextcloud_app
    ports:
      - 8080:80
    restart: unless-stopped
    environment:
      MYSQL_PASSWORD: your_password
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_HOST: db
    volumes:
      - nextcloud_data:/var/www/html

volumes:
  db_data:
  nextcloud_data:

Spustite NexCloud

docker-compose up -d

Choďte cez webový prehliadač na webovú lokalitu v tvare

http://X.X.X.X:8080

Vypíšte si údaje o administrátorovi

kliknite na install

Potom Vám odporúča ďalšie aplikácie, ktoré Vám nextCloud tiež môže poskytnúť

Úspešne nainštalované

Zabbix – Docker Ubuntu 24.04 LTS

Zabbix je open-source softvér pre monitoring IT infraštruktúry, ktorý umožňuje sledovať servery, siete, aplikácie a cloudové služby. Vďaka open-source licencii je úplne zdarma, flexibilný a prispôsobiteľný potrebám organizácie.

Hlavné možnosti využitia Zabbixu:

  1. Monitoring serverov a pracovných staníc – CPU, RAM, disk, procesy.
  2. Monitoring sietí a zariadení – switche, routery, firewally, SNMP zariadenia.
  3. Monitoring aplikácií a služieb – databázy, webové servery, emailové služby, kontajnery.
  4. Vytváranie upozornení a triggerov – Zabbix môže automaticky posielať e-maily, SMS alebo vykonať skript pri problémoch.
  5. Dlhodobá analýza a reportovanie – grafy, histórie, reporty dostupnosti a výkonu.
  6. Automatizácia a integrácie – API umožňuje prepojiť Zabbix s inými systémami (ticketing, Slack, Grafana).

Hlavné vlastnosti Zabbixu:

Podpora notifikácií, eskalácií a automatizovaných akcií.

Open-source a bez licenčných poplatkov.

Centralizovaný monitoring s agentami alebo agentless prístupom.

Webové rozhranie pre prehľadné grafy a dashboardy.

Škálovateľnosť – vhodný od malých prostredí po veľké dátové centrá.

Minimálne hardvérové požiadavky – Zabbix Server

Veľkosť prostrediaPočet hostovCPURAMDiskPoznámky
Malédo ~1001–2 vCPU2–4 GB20–40 GB (SSD odporúčané)cca 5 000 položiek
Stredné100–5002–4 vCPU8–16 GB60–150 GB (SSD)20–50 000 položiek
Veľké1000+8–16+ vCPU32–64+ GB200 GB až TB (SSD)100 000+ položiek

Minimálne požiadavky – Zabbix Frontend (Web UI)

KomponentMinimálne požiadavky
CPU1 vCPU
RAM512 MB – 1 GB
Disk1 GB
Web serverNginx alebo Apache
PHPpodľa verzie Zabbix (napr. PHP 8.x)

Minimálne požiadavky – Zabbix Agent

KomponentMinimálne požiadavky
CPU~0,1 vCPU (veľmi nízke nároky)
RAM128–256 MB
Disk~50 MB
PoznámkyDá sa spustiť takmer na akomkoľvek systéme

Inštalácia

Nainštalujte Docker

sudo apt update
sudo apt install docker.io docker-compose -y
sudo systemctl enable --now docker

Vytvorte priečinok projektu

mkdir ~/zabbix-docker
cd ~/zabbix-docker

Vytvorte docker-compose.yml

version: '3.5'

services:
  mariadb:
    image: mariadb:11.2
    container_name: zabbix-mariadb
    restart: always
    environment:
      MYSQL_DATABASE: zabbix
      MYSQL_USER: zabbix
      MYSQL_PASSWORD: zabbixpass
      MYSQL_ROOT_PASSWORD: rootpass
      TZ: Europe/Bratislava
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_bin
    volumes:
      - db_data:/var/lib/mysql

  zabbix-server:
    image: zabbix/zabbix-server-mysql:latest
    container_name: zabbix-server
    restart: always
    environment:
      DB_SERVER_HOST: mariadb
      MYSQL_DATABASE: zabbix
      MYSQL_USER: zabbix
      MYSQL_PASSWORD: zabbixpass
      ZBX_TIMEZONE: Europe/Bratislava
    ports:
      - "10051:10051"
    depends_on:
      - mariadb

  zabbix-web:
    image: zabbix/zabbix-web-nginx-mysql:latest
    container_name: zabbix-web
    restart: always
    environment:
      DB_SERVER_HOST: mariadb
      MYSQL_DATABASE: zabbix
      MYSQL_USER: zabbix
      MYSQL_PASSWORD: zabbixpass
      ZBX_SERVER_HOST: zabbix-server
      ZBX_SERVER_PORT: 10051
      TZ: Europe/Bratislava
    ports:
      - "8080:8080"

volumes:
  db_data:

Spustite Zabbix

sudo docker-compose up -d

Choďte na webový prehliadač a zadajte IP adresu daného servera v tvare:

http://X.X.X.X:8080

Defaultný login je:

User: Admin
Password: zabbix

WordPress – Docker Ubuntu 24.04

Hardvérové požiadavky – WordPress + Docker (Ubuntu 24.04)

ParameterMinimálne požiadavkyOdporúčané požiadavky
CPU1 vCPU2 vCPU
RAM1 GB2–4 GB
Disk10–15 GB20–40 GB
OSUbuntu 24.04 (64-bit)Ubuntu 24.04 (64-bit)
SwapOdporúčaný pri 1 GB RAMNie je nutný
InternetZákladné pripojenieStabilné pripojenie
DockerDocker CE + Docker ComposeDocker CE + Compose

Inštalácia

Nainštalujte Docker

sudo apt update
sudo apt install -y ca-certificates curl gnupg

Pridajte Docker oficialne Repozitáre

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Nainštalujte docker

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Povoľte, aby sa docker súštal pri boote OS

sudo systemctl enable --now docker

Vytvorte adresár projektu WordPress

mkdir ~/wordpress-docker
cd ~/wordpress-docker

Vytvorte docker-cmpose.yml

nano docker-compose.yml

Skopírujte do neho:

version: "3.9"

services:
  db:
    image: mariadb:10.6
    container_name: wp-db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppass
    volumes:
      - db_data:/var/lib/mysql

  wordpress:
    image: wordpress:latest
    container_name: wordpress-site
    ports:
      - "8080:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppass
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp_data:/var/www/html
    depends_on:
      - db

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: wp-phpmyadmin
    restart: always
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
      MYSQL_ROOT_PASSWORD: rootpass

volumes:
  db_data:
  wp_data:

Uložte to a spustite

sudo docker-compose up -d

Otvorte webový prehliadač, Cez webové stránky:

http://X.X.X.X:8080 - WordPress
http://X.X.X.X:8081 - phpMyAdmin

Spustenie WordPress

Výber jazykovej mutácie

PHPMyAdmin

defaultné príhlásenie

root
rootpass

Wiki.js – Docker Ubuntu 24.04 LTS

Wiki.js je moderný, otvorený a flexibilný wiki systém, ktorý umožňuje tvorbu, správu a zdieľanie dokumentácie a znalostných bázy. Je postavený na Node.js a využíva databázu ako PostgreSQL, MySQL, MariaDB alebo SQLite. Jeho hlavné prednosti sú:

  • Moderné rozhranie (react-based UI)
  • Podpora Markdown a WYSIWYG editora
  • Silná integrácia s autentizačnými systémami (OAuth, LDAP, SAML)
  • Možnosť verzovania stránok a rollbacku zmien
  • Plná podpora multimédií a rozšírení

Technické parametre

ParameterHodnota / odporúčanie
PlatformaNode.js
Podporované DBPostgreSQL, MySQL, MariaDB, SQLite, MSSQL
Minimálne OSLinux (Ubuntu 22.04+), Docker
RAMmin. 512 MB (1 GB+ odporúčané)
CPU1 jadro (viac pre väčšie inštalácie)
Port3000 (default)
Web serverVestavěný Node.js server, odporúča sa reverse proxy (Nginx, Caddy, Traefik)
StorageMin. 1 GB pre databázu a súbory, SSD odporúčané
Docker imageghcr.io/requarks/wiki:2
Podpora HTTPSTreba nastaviť cez reverse proxy (Let’s Encrypt, Caddy, Traefik)

Inštalácia

Urobte update

sudo apt update && sudo apt upgrade -y

Nainštalujte docker

sudo apt install -y docker.io

Povoľte službu, aby sa spúšťala pri boote

sudo systemctl enable --now docker

Nainštalujte docker compose

sudo apt install -y docker-compose

Vytvorenie súboru Docker Compose pre Wiki.js

mkdir ~/wikijs && cd ~/wikijs

Vytvorte docker-compose.yml

nano docker-compose.yml
version: '3'

services:
  wikijs:
    image: ghcr.io/requarks/wiki:2
    container_name: wikijs
    restart: always
    ports:
      - "3000:3000"
    environment:
      DB_TYPE: postgres
      DB_HOST: db
      DB_PORT: 5432
      DB_USER: wikijs
      DB_PASS: wikijs_password
      DB_NAME: wikijs
    depends_on:
      - db

  db:
    image: postgres:15
    container_name: wikijs-db
    restart: always
    environment:
      POSTGRES_USER: wikijs
      POSTGRES_PASSWORD: wikijs_password
      POSTGRES_DB: wikijs
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

Poznámky:

wikijs_password → toto heslo môžete nahradiť silnejším heslom.

Wiki.js bude bežať na porte 3000.

Spustite Wiki.js

sudo docker compose up -d

Teraz otvorte cez webový prehliadač lokalitu

http://X.X.X.X:3000

Spustite inštaláciu

Prihláste sa

Rocket chat – Docker na Ubuntu 24.04 LTS

Rocket.Chat je open-source platforma na tímovú komunikáciu, podobná Slacku alebo Microsoft Teams.
Slúži na chatovanie, zdieľanie súborov, videohovory a spoluprácu v tíme, pričom celý server môžete prevádzkovať lokálne alebo v cloude, takže dáta zostávajú pod Vašou kontrolou.

Kľúčové funkcie:

  • Textový chat v kanáloch a súkromných správach
  • Video a audio hovory
  • Zdieľanie súborov a obrazoviek
  • Integrácie s externými službami (GitHub, Jira, atď.)
  • Podpora LDAP a Single Sign-On

Systémové požiadavky pre Rocket.Chat

Tabuľka – odporúčaný výkon podľa počtu používateľov

Počet používateľovRAM (Rocket.Chat + Mongo)CPUDisk pre Rocket.ChatDisk pre MongoDBPoznámky
1 – 202 GB RAM1–2 vCPU5 GB10–20 GBIdeálne pre malé interné tímy
20 – 504 GB RAM2 vCPU10 GB20–40 GBBežné malé firmy
50 – 2008 GB RAM2–4 vCPU20 GB40–80 GBMongoDB potrebuje viac pamäte
200 – 50016 GB RAM4–6 vCPU30 GB80–200 GBOdporúča sa SSD
500+32 GB RAM+8+ vCPU50 GB200 GB+Potrebné ladenie a replikácia

Operačný systém

KomponentOdporúčanie
OSUbuntu 22.04 / 24.04
Architektúra64-bit
ContainerDocker + Docker Compose

Rocket.Chat Server

ParameterHodnota
CPUmin. 1 vCPU (lepší >2)
RAMmin. 1 GB, odporúčané 2–4 GB
Port3000/tcp
Disk~5–10 GB

Inštalácia

sudo apt update
sudo apt install -y ca-certificates curl gnupg

Pridajte Dockerov GPG kľúč a repozitár

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Inštalácia Docker

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

Ak chcete, aby sa Docker a vaše kontajnery spúšťali automaticky po reštarte servera, použite tieto príkazy:

sudo systemctl enable docker
sudo systemctl start docker 

Vytvorte adresár pre Rocket.Chat

mkdir -p ~/rocket && cd ~/rocket

Vytvoriť súbor docker-compose.yml

nano docker-compose.yaml
services:
  rocketchat:
    image: registry.rocket.chat/rocketchat/rocket.chat:latest
    restart: unless-stopped
    environment:
      PORT: 3000
      ROOT_URL: http://localhost:3000
      MONGO_URL: mongodb://mongo:27017/rocketchat?directConnection=true
      MONGO_OPLOG_URL: mongodb://mongo:27017/local?directConnection=true
    depends_on:
      - mongo
    ports:
      - "3000:3000"

  mongo:
    image: mongo:6.0
    restart: unless-stopped
    command: >
      mongod --oplogSize 128 --replSet rs0 --bind_ip_all
    volumes:
      - ./data/db:/data/db
      - ./data/oplog:/data/oplog

  mongoinit:
    image: mongo:6.0
    command: >
      bash -c "
      sleep 5;
      mongosh --host mongo:27017 --eval '
        rs.initiate();
      '
      "
    depends_on:
      - mongo

Spustiť Rocket.Chat

sudo docker-compose up -d

Teraz, otvorte webový prehliadač a zajte IP adresu daného servera v tvare

http://X.X.X.X:3000

Zobrazí sa Vám úvodné okno

Tu vytvoríme administrátorské konto

Zvolíme Next a vyplníme údaje o organizácií

V poslednom kroku dáme mail na administrátora

Na mail Vám príde overenie

A môžete pracovať s Rocketchat

Mailcow mail server- Docker Ubuntu Server 24.04 LTS

Mailcow je open-source balík aplikácií pre správu e-mailových serverov, ktorý umožňuje jednoduchú inštaláciu, konfiguráciu a bezpečnú prevádzku poštových služieb (SMTP, IMAP, POP3) s moderným webovým rozhraním.

Mailcow slúži na efektívnu správu e-mailovej infraštruktúry: poskytuje poštové schránky, filtráciu spamu a vírusov, zabezpečenú komunikáciu cez TLS a správu domén cez prehľadný webový panel.

Technické požiadavky pre Mailcow

KategóriaPožiadavkaOdporúčanie / Poznámka
Procesor (CPU)min. 1 GHzViacjadrový procesor (x86_64 alebo ARM64) pre lepší výkon
Pamäť (RAM)min. 6 GiB + 1 GiB swap4 GiB možné len bez antivírusu a indexovania; pre väčšie nasadenie 16 GiB+
Diskmin. 20 GiB (bez e-mailov)Odporúča sa SSD/NVMe disk kvôli rýchlosti
Architektúrax86_64 alebo ARM64ARM64 podporovaný od Docker verzie 24+
Operačný systémDebian 11–13, Ubuntu 24.04+, AlmaLinux 8/9, Rocky Linux 9Používajte čistú inštaláciu bez predinštalovaného Dockeru zo snapu
Docker Engine≥ 24.0.0Vyžaduje sa funkčný Docker daemon
Docker Compose≥ 2.0 (plugin alebo standalone)Spúšťa kontajnery Mailcow stacku
DNSFQDN, MX, A, AAAA, PTR, SPF, DKIM, DMARCNutné pre správne doručovanie a prijímanie e-mailov
Sieť a porty25, 80, 443, 465, 587, 993, 995, 4190, 53 (TCP/UDP)Port 25 nesmie byť blokovaný poskytovateľom
IPv4 / IPv6statická IP adresa odporúčanáNutný správny PTR (reverse DNS) záznam
Úložisko e-mailovzávisí od počtu používateľovPre desiatky GB pošty použiť väčší disk (napr. 100 GiB+)
BezpečnosťFirewall, SSL/TLS certifikáty (Let’s Encrypt)HTTPS a SMTPS sú nevyhnutné pre bezpečný prenos
Voliteľné komponentyAntivírus (ClamAV), Antispam (Rspamd), Fulltext (Solr)Možno vypnúť pre úsporu pamäte
Autentifikácia (MFA)Podpora TOTP (napr. Google Authenticator, Authy, Bitwarden)MFA dostupné pre administrátorov aj používateľov webmailu

Priprava PortForwarding

80TCPHTTP (overovanie certifikátu Let’s Encrypt)Web + ACME
443TCPHTTPS (administrátorské rozhranie Mailcow, webmail, ActiveSync)Webový prístup
25TCPSMTPPrichádzajúca pošta z iných poštových serverov
465TCPSMTPS (zabezpečený SMTP)Odchádzajúca pošta (klienti)
587TCPSubmission (STARTTLS SMTP pre klientov)Odchádzajúca pošta (klienti)
993TCPIMAPSPrichádzajúca pošta pre klientov
995TCPPOP3S (voliteľné)Prichádzajúca pošta pre klientov
4190TCPSieve (správa poštových filtrov)Voliteľné
53TCP/UDPDNS (iba ak Mailcow používa DNS v rámci Dockeru)Voliteľné

Uptade a Upgrade

Je potrebné urobiť update a Upgrade systéme

sudo apt update && sudo apt upgrade -y

Najjednoduchší spôsob je nainštalovať Docker z oficiálneho repozitára Docker (nie z vstavaného repozitára Ubuntu).

Pridajte oficiálny GPG kľúč a repozitár Dockeru

sudo apt install ca-certificates curl gnupg -y
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Nainštalujte si plugin Docker Engine + Compose

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

Overte inštaláciu

docker --version
docker compose version

Príklad

Docker version 27.x.x, build ...
Docker Compose version v2.x.x

Inštalácia Mailcow

Teraz, keď je Docker pripravený, nainštalujte samotný Mailcow.

Nainštalujte git (ak nie je nainštalovaný)

sudo apt install git -y

Klonovanie repozitár Mailcow

cd /opt
sudo git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized

Vygeneruj configuračný súbor

sudo ./generate_config.sh

Spustite Mailcowm

sudo docker compose pull
sudo docker compose up -d

Choďte cez mailový server
napr.

https://mail.ibasterisk.eu>

default login je:

Username: admin
Password: moohoo

Je potrebné voliť možnosť Log in as admin

Pridanie domény

Je púotrebné ísť do Email a konfigurácia

Klilnite na Add Domain

Vypíšeme doménu

V spodnej časti budú možnosti

  • Add domain only
  • Add domain and restart SOGo

Je dôležité zvoliť Add domain and restart SOGo

Vytvorenie nového administrátora

Volíme systém configuration

Add administrator

Vypĺňame username a password, je možné dať aj heslo vygenerovať

Vytvorenie mailového konta

Ideme do E-mail a Configuration

Volíme Add mailbox

Vypíšeme údaje

Prihlasenie sa cez webové rohranie vytvorenou mailovou adresou

Je potrebné vybrať Log in as user

Nastavenie MFA užívateľa

A vieme si vybrať z možností

Two-factor authentification pre administratora

Two-factor authentification je nastavena automaticky pri vytvorení nového administrátora, ak si želáte tieto nasatvenia modifikovať, tak sa to robí v System >> configuration

Vytváranie záznamov

Vytvoril som A záznam na verejnú IP

mail.ibasterisk.eu	1800	A	109.230.12.223

MX záznam

ibasterisk.eu	1800	MX	10 mail.ibasterisk.eu

TXT záznam

ibasterisk.eu	1800	TXT	v=spf1 a mx include:_spf.ibasterisk.eu -all

dmarc

_dmarc.ibasterisk.eu	1800	TXT	v=DMARC1; p=none; pct=100; rua=mailto:p

a vytvoriť dkim

dkim.ibasterisk.eu	1800	TXT	v=DKIM1; p=MIaAutorizačný_kód_vygenerovaný_na_emailovom_serveryIBIjANBgkqhkiG9w0BAQEFA

Ďalšie TXT záznamy, aby prešli na o365

ibasterisk.eu	1800	TXT	v=spf1 a mx include:_spf.ibasterisk.eu -all
ibasterisk.eu	1800	TXT	v=spf1 include:spf.protection.outlook.com
ibasterisk.eu	1800	TXT	v=spf1 ip4:109.230.12.223 include:spf.prot
	

TXT pre gmailNa google

ibasterisk.eu	1800	TXT	v=spf1 ip4:109.230.12.223 include:_spf.google.com ~all

Vysvetlenia

@ do poľa názvu, ktorý bude predstavovať názov hlavnej domény.
v=spf1 označuje, že ide o záznam SPF a verzia je SPF1.
mx znamená, že všetci hostitelia uvedení v záznamoch MX môžu odosielať e-maily pre vašu doménu a všetci ostatní hostitelia sú zakázaní.
~all znamená, že e-maily z vašej domény by mali pochádzať iba z hostiteľov uvedených v zázname SPF. E-maily od iných hostiteľov budú označené, ako sfalšované.

A Záznam určuje, na akú IP adresu bude doména nasmerovaná. Pomocou nastavení a záznamu možno vytvoriť doménu tretieho rádu už existujúcu doméne.
AAAA záznam určuje, akou adresu IPv6 bude doména nasmerovaná. Tu sa pre presmerovanie použije záznam alebo AAAA záznam rozhoduje o nastavení internetových prehliadačov.
CAA Definuje politiku vystavení SSL/TLS certifikátu na zvolenú doménu. Ovplyvňuje certifikačnú autoritu, ktorú možno vystaviť pre vyplnenú doménu certifikátu SSL/TLS.
CNAME slúži k presmerovaniu subdomény na inú doménu. Názov CNAME musí byť vždy vyplnený. Alias ​​sa zadáva vo forme celého názvu domény (napr. mail.ibasterisk.sk).
MX Určuje mailserver, na, ktorý budú smerovať e-maily zaslané na túto doménu. Vždy sa použije celý doménový názov serveru. Ak máte iba jeho IP adresu, nastavte najprv, ako záznam a jeho doménový názov potom vyplňte pole Mailserver.
NS Nastavuje sa nameserver pre konkrétnu subdoménu. Z určeného menného serveru je určené správanie subdomény. Ostatné záznamy DNS sú naďalej brány z nastavení nameserverov na menej.
SRV Pomocou SRV záznamov je možné nájsť server obsluhujúcej vybranú službu v cieľovej doméne. Zvyčajne sú používané vo spojení so štandardizovanými protokolmi, ako sú XMPP, SIP alebo LDAP.
SSHFP Pri použití technológie DNSSEC môžete využívať záznam typu SSHFP pre ukladanie otlačkov verejných kľúčov pre protokol SSH (nemusíte potom overovať otlačok kľúča ručne pri prvom spojení).
TLSA Pri použití technológie DNSSEC môžete využívať záznam typu TLSA pre ukladanie certifikátov SSL použitých na menej.
TXT stačí vložiť do DNS ľubovoľný text. Text môže byť dlhý maximálne 255 znakov. Používa sa napríklad pre podpis odoslaných emailov (DKIM, SPF).

Dark-Mode

A na záver mailcown podporuje Darkmode. Tak nastavuje pri to mesiačiku.

Týmto sa to zapína a vypína 🙂

Upgrade na noviu verziu Malcow

Dobre je ako prvé si urobit zálohu

Ako prvé vojdeme do adresára

cd /opt/mailcow-dockerized

Urobíme zálohu

sudo ./helper-scripts/backup_and_restore.sh backup all

Zobrazí sa nám hláška

 Backup location (absolute path, starting with /):  
/var/backups/mailcow -----cesta
/var/backups/mailcow is not a directory ----- nieje vytvorený adresár je potrebné ho vyttoviť
Create it now? [y|N] y ----- stlačte Y 
Using 1 Thread(s) for this run.
Notice: You can set the Thread count with the THREADS Variable before you run this script.
Using /var/backups/mailcow as backup/restore location.

Následne spustime príkaz pre update

./update.sh