Certifikačná autorita (CA) Let’s Encrypt (LE) vydáva bezplatné TLS certifikáty, ktorá slúžia pre šifrovanú komunikáciu medzi serverom a klientom. O tom ako CA LE funguje som písal v roku 2019, ale aj nedávno keď sme nastavovali reverzný proxy server Nginx. Ak sú certifikáty vydávané pre verejnú doménu, tak to funguje za pomoci certbot a acme protokolu veľmi jednoducho. Pre privátne domény sa certifikáty nevydávajú aby nemohli byť zneužité. Avšak pre subdomény sa od januára 2018 vydávajú tzv wildcard certifikáty. Takýto certifikát je možné získať aj pre privátnu subdoménu. Ako som postupoval krok po kroku sa dozviete ak budete čítať ďalej.
Obsah
- Toplógia siete
- Získanie cert. pre verejnú doménu
- Vytvárame privátnu subdoménu
- Konfigurácia virtualhost
- Konfigurácia server block
- Šifrovanie v rámci LAN (ne)potrebujeme
- Získanie certifikátov od LE
- Rekonfigurácia server block v Nginx
- Záver
- Použitá literatúra
Topológia siete
Vzhľadom k tomu, že budeme pracovať na troch rôznych zariadeniach, tak považujem za dôležité aby bola topológia siete vysvetlená hneď na začiatku (na generovanie certifikátov to samozrejme nemá žiadny vplyv). Ak sa pozrieme na nasledujúci obrázok, tak celkom na pravo je backendový Apache2 web server na ktorom budú uložené webové adresáre (tam budeme konfigurovať aj vhosts). Ako frontend bude použitý reverzný proxy server Nginx na ktorom budú uložené certifikáty pre subdomény. Obidva servery sú linuxové kontajnery. DNS záznamy budú nastavené na lokálnom DNS resolvery (pfSense), ktorý je tiež virtuálny stroj KVM. Či budeme používať virtuálne stroje, kontajnery, alebo fyzické stroje je úplne jedno.

Získanie cert. pre verejnú doménu
Majme verejnú doménu druhého radu example.com. Pre túto doménu viem získať certifikát veľmi jednoducho (predpokladajme že certbot pre nginx je nainštalovaný a funguje správne). Na generovanie certifikátov použijeme nasledujúci príkaz.
sudo certbot --nginx -d example.com -d www.example.com
To je všetko čo musíme pre získanie certifikátu spraviť. Tento príkaz hovorí aby certbot získal certifikát pre doménu example.com a subdoménu www.example.com (áno v tomto prípade je www subdoména a na DNS servery musí byť k nej CNAME záznam). Ak by sme chceli mať viac „verejných“ subdomén, tak na DNS servery vytvoríme ďalšie CNAME na doménu napr. cloud.example.com, wiki.example.com atď. a príkaz na získanie cert. bude následovný.
sudo certbot --nginx -d example.com -d www.example.com -d cloud.example.com -d wiki.example.com
My však chcem získať certifikát pre subdoménu, ktorá má byť privátna, to znamená, že z internetu nie je dostupná. Najprv si privátnu subdoménu poďme vytvoriť.
Vytvárame privátnu subdoménu
O statických DNS záznamoch som tiež písal nedávno, takže to prejdeme len v rýchlosti. Na obrázku som nastavil 3 subdomény. Doména example.com a subdoména www.example.com sú zároveň verejné a na DNS servery k ním existujú A resp. CNAME záznamy. Subdomény cloud.example.com a wiki.example.com existujú len v našom lokálnom DNS resolvery. Tieto subdomény nie sú viditeľné z internetu.

Ak po uložení Save a potvrdení Apply Changes zadáme do webového prehliadača jednú zo subdomén cloud.example.com, alebo wiki.example.com, tak budeme presmerovaný na defaultný súbor nginx. Dôvod je ten, že kvázi CNMAE už existujú, ale nemáme nakonfigurované virtuálhosts a server block na reverznom proxy servery.
Konfigurácia virtualhost
Predpokladom je už nainštalovaný a plne funkčný webový server Apache2. Teraz môžeme vytvoriť prvý aj druhý virtualhost. Ja prevádzkujem Apache2 server v linuxovom kontajnery, takže sa cez SSH prihlásim do LXC a postupujem následovne:
Prvý virtualhost
sudo mkdir /var/www/html/www.example.com/cloud
sudo nano /etc/apache2/sites-available/cloud.example.com.conf
<VirtualHost *:80>
ServerAdmin admin@cloud.example.com
ServerName cloud.example.com
DocumentRoot /var/www/html/www.example.com/cloud/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
sudo chown www-data:www-data -R /var/www/html/www.example.com/cloud
sudo a2ensite cloud.example.com.conf
sudo systemctl reload apache2
sudo echo "<html><head><title>cloud</title></head><body><h1>This is cloud on example.com</h1></body></html>" | sudo tee /var/www/html/www.example.com/cloud/index.html
Druhý virtualhost
sudo mkdir /var/www/html/www.example.com/wiki
sudo nano /etc/apache2/sites-available/wiki.example.com.conf
<VirtualHost *:80>
ServerAdmin admin@wiki.example.com
ServerName wiki.example.com
DocumentRoot /var/www/html/www.example.com/wiki/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
sudo chown www-data:www-data -R /var/www/html/www.example.com/wiki
sudo a2ensite wiki.example.com.conf
sudo systemctl reload apache2
sudo echo "<html><head><title>wiki</title></head><body><h1>This is wiki on example.com</h1></body></html>" | sudo tee /var/www/html/www.example.com/wiki/index.html
Ak si myslíme, že teraz zadaním url adries cloud.example.com, alebo wiki.example.com do webového prehliadača uvidíme obsah index.html súborov, tak sa mýlime. Stále uvidíme defaultný súbor nginx, pretože všetka komunikácia je presmerovaná na IP adresu reverzného proxy servera. Ak sa konečne chceme dostať na naše spomínané virtualhosts musíme vytvoriť server block konfiguráciu na reverznom proxy servery.
Konfigurácia server block
Obdobou virtualhost na Apache2 servery je server block na Nginx. Do jedného konfiguračného súboru server block na Nginx servery som umiestnil obidva subdomény. Čiže najprv sa cez SSH prihlásime do LXC reverzného proxy servera a začneme vytvárať konfiguráciu.
sudo nano /etc/nginx/sites-available/subdomain.example.com
# -----------cloud-subdomain------------#
server {
listen 80;
server_name cloud.example.com;
location / {
proxy_pass http://192.168.1.106;
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;
}
}
# -----------wiki-subdomain------------#
server {
listen 80;
server_name wiki.example.com;
location / {
proxy_pass http://192.168.1.106;
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;
}
}
Teraz skontrolujeme syntax a preveríme či je konfigurácia v poriadku. Vytvoríme symbolicky link odkiaľ bude nginx konfiguráciu čítať a reloadneme server pre načítanie novej konfigurácie.
sudo nginx -t
sudo ln -s /etc/nginx/sites-available/subdomain.example.com /etc/nginx/sites-enabled/subdomain.example.com
sudo systemctl reload nginx
Ak si myslíme, že teraz zadaním url adries cloud.example.com, alebo wiki.example.com do webového prehliadača uvidíme obsah index.html súborov, tak máme pravdu. Teraz konečne vidíme obsah našich lokálnych subdomén a v rámci LAN ich môžeme plnohodnotne využívať. Takto môže byť riešený napr. intranet v podnikovej sfére. Avšak vidíme, že weby sú nezabezpečené, resp. komunikácia medzi serverom a klientom nie je šifrovaná.
Šifrovanie v rámci LAN (ne)potrebujeme
Ak v rámci lokálnej (resp. podnikovej) siete dôverujeme klientom, tak nepotrebujeme komunikáciu medzi klientom a serverom šifrovať. Ak je však podniková sieť veľká a nemôžeme každej osobe dôverovať, tak sa vyžaduje TLS spojenie. Jednou z možností je vytvorenie certifikátov pomocou vlastnej CA. Tieto certifikáty určite nebude poznať žiadny webový prehliadač a môže to vyzerať napr. takto.

Aj keď v tomto prípade je spojenie šifrované (certifikát je platný), tak webový prehliadač nepozná CA a spojenie považuje za nezabezpečené. Preto je vhodnejšie použiť CA od dôveryhodného vydavateľa a tým môže byť napr. LE. Táto CA je dôveryhodná pre nasledujúce platformy.
Získanie certifikátov od LE
Keď chceme získať certifikát od LE, tak servery LE musia overiť, že skutočne máme kontrolu nad doménou a to sa deje prostredníctvom výzvy (challenge). Tieto chellenges sú pekne popísane na LE webe.
- HTTP-01 challenge
- DNS-01 challenge
- TLS-SNI-01
- TLS-ALPN-01
Vo väčšine prípadov sa používa HTTP-01 challege, ale pre wildcard musíme použiť DNS-01 challenge. V podstate to funguje tak, že LE poskytne klientovi ACME token. Klient vytvorí záznam TXT odvodený z tohto tokenu, kľúča vášho účtu a umiestni tento záznam na _acme-challenge.<YOUR_DOMAIN>. Potom LE požiada systém DNS o tento záznam. Ak nájde zhodu, môžete pristúpiť k vydaniu certifikátu!
Takže poďme na to
sudo certbot -d *.example.com --manual --preferred-challenges dns certonly
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for example.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.
Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.example.com with the following value:
X7RMZ1ompP_xXGWWPPT8TVUQ8fvGPAg-PkaxsadZFIo
Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presunieme sa na server freenom, kde zadáme vygenerovaný kód ako TXT záznam

Teraz musíme chvíľu čakať, pokiaľ sa na DNS servery prejavia zmeny. Na niektorých DNS serveroch je to rýchle, na iných je potrebné čakať aj desiatky minút. Na freemom sa zmena prejavila do niekoľkých minút. Či je TXT záznam na servery v poriadku môžeme overiť príkazom dig
dig -t txt +short _acme-challenge.example.com
ak bude výsledkom kľúč, ktorý sme poskytli serveru vo forme TXT záznamu
X7RMZ1ompP_xXGWWPPT8TVUQ8fvGPAg-PkaxsadZFIo
je to OK a môžeme dať enter
Press Enter to Continue
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/example.com-0001/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/example.com-0001/privkey.pem
Your cert will expire on 2022-04-03. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Certifikát sme úspešne získali na 90 dní. Po 90 dňoch musíme spraviť rovnakú procedúru. Nie je to nič zložité. Ja v súčasnej dobe stále používam doménu od freenom (vrátane DNS serverov). Na automatizáciu tohto procesu sa používajú pluginy, ktoré sú kompatibilné s certbot. Pre freenom, takýto plugin nie je, ale našiel som pythonovsky plugin, ktorý tento proces plne automatizuje. Jedna sa o plugin certbot-dns-freenom. Avšak tomuto pluginu sa budem venovať niekedy inokedy, zatiaľ mi postačuje ručná obnova 😀
Rekonfigurácia server block v Nginx
Naš konfiguračný súbor zatiaľ nemá potuchy o nejakých certifikátoch, preto musíme serveru Nginx oznámiť cestu kde sa certifikáty nachádzajú. Upravený konfiguračný súbor pre obidva subdomény bude vyzerať následovne.
# -----------cloud-subdomain------------#
server {
server_name cloud.example.com;
location / {
proxy_pass http://192.168.1.106;
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;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/example.com-0001/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com-0001/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = cloud.example.com) {
return 301 https://$host$request_uri;
}
listen 80;
server_name cloud.example.com;
return 404;
}
# -----------wiki-subdomain------------#
server {
server_name wiki.example.com;
location / {
proxy_pass http://192.168.1.106;
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;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/example.com-0001/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com-0001/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = wiki.example.com) {
return 301 https://$host$request_uri;
}
listen 80;
server_name wiki.example.com;
return 404;
}
Ak po reloade Nginix servera zadáme do url cloud.example.com, alebo wiki.example.com, tak zistíme, že web server z prehliadačom komunikuje šifrovane (šifrovanú komunikáciu symbolizuje visiaci zámok pred url adresou).
Záver
Privátne subdomény v rámci lokálnej siete môžeme vytvoriť toľko, koľko potrebujeme. Výhoda je, že certifikáty sú dôveryhodné aj keď subdomény sú privátne a nie sú viditeľné z internetu. Pokiaľ máme v správe množstvo serverov, tak je vhodné tento proces automatizovať. ako som už v blogu spomenul, veľmi som sa automatizácii nevenoval. Budem však hľadať riešenia aby som tento proces v budúcnosti mal plne automatizovaný. Z pohľadu jednoduchosti bude zrejme najvhodnejšie využiť certbot-dns-freenom, alebo zmeniť DNS server na taký, pre ktorý existuje vhodný DNS plugin (napr. clouflare).
Použitá literatúra
- Všetko o Let’s Encrypt na root.cz
- Kompatibilita certifikátov na LE
- Freenom-dns-updater
- Configuring multiple subdomains on an NGINX webserver
- Setting up a Letsencrypt wildcard certificate on a private domain/IP
- How to Install free SSL on your Subdomain using LetsEncrypt
- freenom DNS Authenticator plugin for Certbot