
U prošlosti sam letsencrypt koristio za besplatne potvrde. Nisam ga uspješno koristio od prelaska na docker / kestrel / nginx. Sve se to danas promijenilo, a ja sam vraški dobro shvaćao što radim da to uspije.
Cijeli ovaj Unix, docker, nginx, prilično su novi (za mene), pa je možda to jednostavno nešto što mi je cijelo vrijeme nedostajalo. Unatoč tome, nadam se da će ovo pomoći nekome drugome ili meni nekoliko mjeseci ako odlučim to ponoviti.
Izvorno postavljanje
Imam glavno web mjesto .net, hostirano putem kestrela, pokrenuto na dockeru, s obrnutim proxyjem putem nginxa. Do sada je to obrnuto proksiranje iz nginxa radilo samo preko http / porta 80. Ne znam puno o obrnutim proxyjima. Po zvuku može primati zahtjeve i prosljeđivati ih na određeno mjesto u ime podnositelja zahtjeva. U mom slučaju, nginx spremnik prima http zahtjeve, a nginx prosljeđuje taj zahtjev na moje jezgro .net jezgre koje hostira kestrel. Je li to točno? Nadam se!
Kao što je prethodno spomenuto, nginx je radio samo s http prometom. Imao sam puno problema s radom s https-om, originalna konfiguracija je sljedeća:
docker-compose:
version: '3.6'services: kritner-website-web: image: ${DOCKER_REGISTRY}/kritnerwebsite expose: - "5000" networks: - frontend restart: always container_name: kritnerwebsite_web kritner-website-nginx: image: nginx:latest ports: - "80:80" volumes: - ../src/nginx/nginx.conf:/etc/nginx/nginx.conf depends_on: - kritner-website-web networks: - frontend restart: always container_name: kritnerwebsite_nginx
networks: frontend:
U datoteci docker-compose koristim dva odvojena spremnika - web mjesto koje izlaže port 5000 (na docker mreži, a ne javno) i nginx koji radi na portu 80.
nginx.conf
worker_processes 4; events { worker_connections 1024; } http { sendfile on; upstream app_servers { server kritner-website-web:5000; } server { listen 80; location / { proxy_pass //app_servers; proxy_redirect off; 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-Host $server_name; } }}
U konfiguracijskoj datoteci postavljamo uzvodni poslužitelj s istim imenom koji zovemo našu uslugu spremnika iz datoteke za sastavljanje dockera kritner-website-web:5000
.
Imajte na umu da se sve gore navedeno može pronaći na ovom mjestu urezivanja u spremištu moje web stranice.
Unesite HTTPS
Letsencrypt je tijelo za izdavanje certifikata koje nudi besplatne certifikate koji pomažu u zaštiti vaše web stranice. Zašto je HTTPS putem TLS-a važan? Pa, puno je toga i kako to djeluje. Osnovna ideja je da je promet korisnika šifriran na bilo kojem kraju prije nego što se pošalje na drugi kraj. To znači da ako ste na javnom wifiju i na https-u, netko tko je takoreći "nanjušio žicu", vidio bi da se događa promet, ali ne i sadržaj spomenutog prometa. Budući da oba kraja šifriraju / dešifriraju navedeni promet istim ključem šifriranja.
Da ste na http mjestu, taj bi se promet slao naprijed-natrag u običnom tekstu. Znači da postoji opasnost od prisluškivanja vaših podataka! Možda ću kad tad napisati nešto više o šifriranju. (* napomena za sebe *) Pogotovo jer je to nešto što radim kao svoj svakodnevni posao!
letsencrypt je usluga koju sam prije koristio. Postoje razne implementacije kojima se pokušava učiniti što lakšim korištenje. Istraživanjem za ovaj post, dogodio sam se na ovome.
Iako ovu stranicu nisam pronašao do sada, bila bi korisna prije početka moje avanture. Želio sam koristiti letsencrypt zajedno sa svojim web mjestom docker kontejnera i nginxom, uz što manje održavanja. certifikati letsencrypt dobri su samo 90 dana.
U svom istraživanju dogodio sam se na docker slici linuxserver / letsencrypt koja obećava upotrebu nginxa, generiranje letsencrypt certifikata i automatsku obnovu. Zvuči strašno! Dok se dokumentacija slike čini uglavnom adekvatnom - za nekoga tko je dobro upućen u cijeli taj postupak. Otkrio sam da nedostaje. Cijeli postupak postavljanja trebao mi je neko vrijeme da shvatim. Stoga ovaj post, nadam se da ću pomoći sljedećoj osobi ili opet meni u budućnosti!

Borbe
Najviše sam se mučio prilikom postavljanja i rada ove slike linuxserver / letsencrypt:
- Kako "rade" količine dockera i njihov odnos s ovim spremnikom
- Kako postaviti volumen za korištenje moje konfiguracije (vezano uz gornju točku) - U početku sam imao puno problema dok nisam shvaćao zašto su se moje postavke promijenjene na spremniku mijenjale prilikom ponovnog učitavanja spomenutog spremnika (jer je to ono što oni trebao učiniti)
- Kako postaviti ispravnu nginx konfiguraciju - gdje je staviti i što u nju.
Dockerovi svezaci
Količine doker-a (doc):
Volumeni su preferirani mehanizam za trajne podatke koje generiraju i koriste Docker spremnici. Iako montiranja vezanja ovise o strukturi direktorija glavnog računala, volumenom u potpunosti upravlja Docker. Svesci imaju nekoliko prednosti u odnosu na nosače vezanjaletsencrypt ima puno konfiguracije koja ide uz to. Trebalo mi je neko vrijeme da shvatim, ali trebao mi je volumen koji se preslikao iz direktorija na hostu dockera u određeni direktorij na letsencrypt slici. Na kraju sam to postigao u datoteci za sastavljanje ovako:
volumes: - ${DOCKER_KRITNER_NGINX}:/config - ./nginx.conf:/config/nginx/site-confs/default
Prva stavka u polju ( ${DOCKER_KRITNER_NGINX}:/config
) uzima novu varijablu okruženja koja mapu hosta (definiranu u varijabli) preslikava u /config
sam spremnik dockera. To znači da će domaćin dockera (na putu env var) sadržavati istu konfiguraciju kao spremnik dockera na sekundarnom dijelu mapiranja volumena ( /config
)
Druga stavka ( ./nginx.conf:/config/nginx/site-confs/default
) preslikava datoteku mojih lokalnih spremišta nginx.conf (datoteka u kojoj sam postavio obrnuti proxy) da nadjača /config/nginx/site-confs/default
datoteku na hostu i spremniku dockera .
Cjelovit popis datoteka koje sam na kraju trebao izmijeniti u svojoj situaciji bio je:
/config/dns-conf/dnsimple.ini
/config/nginx/site-confs/default
dnsimple.ini
Konfiguracija je dodati svoj API ključ i …/default
kućama Nginx konfiguracija.
Konačna default
konfiguracija s kojom sam završio je:
upstream app_servers { server kritnerwebsite:5000;}
## Version 2018/09/12 - Changelog: //github.com/linuxserver/docker-letsencrypt/commits/master/root/defaults/default
# listening on port 80 disabled by default, remove the "#" signs to enable# redirect all traffic to httpsserver { listen 80; server_name kritnerwebsite; return 301 //$host$request_uri;}
# main server blockserver { listen 443 ssl;
# enable subfolder method reverse proxy confs include /config/nginx/proxy-confs/*.subfolder.conf;
# all ssl related config moved to ssl.conf include /config/nginx/ssl.conf; # enable for ldap auth #include /config/nginx/ldap.conf;
client_max_body_size 0;
location / { proxy_pass //app_servers; proxy_redirect off; 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-Host $server_name; }
}
# enable subdomain method reverse proxy confsinclude /config/nginx/proxy-confs/*.subdomain.conf;# enable proxy cache for authproxy_cache_path cache/ keys_zone=auth_cache:10m;
Nekoliko je promjena u odnosu na zadane postavke, koje ću pokušati istaknuti sljedeće.
upstream app_servers { server kritnerwebsite:5000;}
Iznad je prilično cool, jer docker ima vlastiti interni DNS (pretpostavljam?). Uzvodni poslužitelj možete postaviti pod imenom spremnika, u mom slučaju "kritnerwebsite". (Napomena: promijenio sam ga u odnosu na ranije u postu, koji je bio "kritner-web-web-web".)
# listening on port 80 disabled by default, remove the "#" signs to enable# redirect all traffic to httpsserver { listen 80; server_name kritnerwebsite; return 301 //$host$request_uri;}
Uncommented out this section from the default, applied my server_name of “kritnerwebsite”
# main server blockserver { listen 443 ssl;
# enable subfolder method reverse proxy confs include /config/nginx/proxy-confs/*.subfolder.conf;
# all ssl related config moved to ssl.conf include /config/nginx/ssl.conf; # enable for ldap auth #include /config/nginx/ldap.conf;
client_max_body_size 0;
location / { proxy_pass //app_servers; proxy_redirect off; 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-Host $server_name; }
}
In the above, it’s mostly from the “default” save for “location” and everything within that object. Here, we’re setting up the reverse proxy to forward requests to “/” (anything) to our //app_servers
(kritnerwebsite as per our upstream).
docker-compose.yml
Our docker compose file didn’t change a *whole* lot from the initial. There were a few notable changes, which I’ll also get into describing:
version: '3.6'services: nginx: image: linuxserver/letsencrypt ports: - "80:80" - "443:443" volumes: - ${DOCKER_KRITNER_NGINX}:/config - ./nginx.conf:/config/nginx/site-confs/default depends_on: - kritnerwebsite networks: - frontend container_name: nginx environment: - PUID=1001 # get on dockerhost through command "id "" - PGID=1001 - [email protected] - URL=kritner.com - SUBDOMAINS=www - TZ=America/NewYork - VALIDATION=dns # using dns validation - DNSPLUGIN=dnsimple # via dnsimple, note there is additional configuration require separate from this file # - STAGING=true # this should be uncommented when testing for initial success, to avoid some rate limiting
kritnerwebsite: image: ${DOCKER_REGISTRY}/kritnerwebsite networks: - frontend expose: - "5000" restart: always container_name: kritnerwebsite networks: frontend:
for the new parts:
nginx: image: linuxserver/letsencrypt
Using a different image — linuxserver/letsencrypt instead of nginx. This image has nginx included, but also certbot, along with a cronjob to run certbot at application start.
ports: - "80:80" - "443:443"
Now we’re using both http and https ports (though note, we’re redirecting http calls to https via the nginx config).
volumes: - ${DOCKER_KRITNER_NGINX}:/config - ./nginx.conf:/config/nginx/site-confs/default
Already discussed earlier in the post, we’re using these volumes to properly set up the nginx configuration, with our dnsimple api key, as well as our reverse proxying to the kritnerwebsite.
environment: - PUID=1001 # get on dockerhost through command "id " - PGID=1001 - [email protected] - URL=kritner.com - SUBDOMAINS=www - TZ=America/NewYork - VALIDATION=dns # using dns validation - DNSPLUGIN=dnsimple # via dnsimple, note there is additional configuration require separate from this file # - STAGING=true # this should be uncommented when testing for initial success, to avoid some rate limiting
Environment variables needed as per the letsencrypt documentation can be found here.
- PUID/PGID — get on dockerhost through command “id ”
- Email — well, your email (used for cert expiration emails apparently)
- URL — the main domain URL
- subdomains — any subdomains to the URL to be certified
- TZ — timezone
- Validation — the type of validation to do — I’m using DNSimple, so i needed DNS in this field. Other options are html, tls-sni
- dnsplugin — dnsimple — other options are
cloudflare
,cloudxns
,digitalocean
,dnsmadeeasy
,google
,luadns
,nsone
,rfc2136
androute53
as per the letsencrypt documentation - Staging=true — I used this for testing out all my various attempts prior to getting it working. letsencrypt has rate limiting when not running in staging mode (or at least in staging it’s harder to run up against).
All the above changes, experimenting, failing, and then finally succeeding can be found in this pull request.
The final result?

and from //www.ssllabs.com/ —

Not an “A+”, but really not bad for using one pre-built docker image for my HTTPs needs!
Related:
- Going from an “A” to an “A+” on ssllabs.com