Sådan opsættes dit websted til den søde, søde HTTPS med Docker, Nginx og letsencrypt

Jeg har tidligere brugt letsencrypt til gratis certs. Jeg har ikke brugt det med succes, siden jeg flyttede over til docker / kestrel / nginx. Det hele ændrede sig i dag, og jeg havde en helvede tid på at finde ud af, hvad jeg gjorde for at få det til at fungere.

Hele denne Unix, docker, nginx, ting er ret nyt (for mig), så måske er det bare noget simpelt, jeg manglede hele tiden. Ikke desto mindre håber jeg, at dette vil hjælpe en anden eller mig flere måneder nede, hvis jeg beslutter at gøre det igen.

Oprindelig opsætning

Jeg har en .net-kernewebsite, der hostes via kestrel, kører på docker, med en omvendt proxy via nginx. Indtil nu fungerede den omvendte proxy fra nginx kun over http / port 80. Jeg kender ikke meget om reverse proxies. Fra lyden af ​​det kan det modtage anmodninger og videresende dem til et bestemt sted på vegne af rekvirenten. I mit tilfælde modtager nginx-containeren http-anmodninger, og nginx videresender den anmodning til min kestrel-hostede .net-kerneside. Er det rigtigt? Forhåbentlig!

Som tidligere nævnt arbejdede nginx kun med http-trafik. Jeg havde mange problemer med at få det til at fungere med https, den oprindelige konfiguration er som følger:

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:

I docker-compose-filen bruger jeg to separate containere - webstedet, der udsætter port 5000 (på docker-netværket, ikke offentligt) og nginx, der fungerer på port 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; } }}

I konfigurationsfilen opretter vi en upstream-server med det samme navn, som vi kalder vores containertjeneste fra docker-compose-filen kritner-website-web:5000.

Bemærk, alt det ovenstående kan findes på dette forpligtelsespunkt på min websides arkiv.

Indtast HTTPS

Letsencrypt er en certifikatmyndighed, der tilbyder gratis certs for at hjælpe med at sikre dit websted. Hvorfor er HTTPS via TLS vigtigt? Nå, der er meget, og hvordan det fungerer. Grundideen er, at brugerens trafik krypteres i begge ender, inden den sendes til den anden ende. Dette betyder, at hvis du er på offentlig wifi, og på https, ville en person, der "sniffede ledningen" så at sige, se, at der sker trafik, men ikke indholdet af den nævnte trafik. Da begge ender krypterer / dekrypterer trafikken med den samme krypteringsnøgle.

Hvis du var på et http-sted, ville denne trafik blive sendt frem og tilbage i almindelig tekst. Det betyder, at dine data er i fare for at blive aflyttet! Måske skriver jeg lidt mere om kryptering på et eller andet tidspunkt. (* note til dig selv *) Især da det er noget, jeg laver som mit daglige job!

letsencrypt er en tjeneste, jeg har brugt før. Der er forskellige implementeringer for at forsøge at gøre det så let som muligt at bruge. Gennem research til dette indlæg, skete jeg på dette.

Selvom jeg ikke havde fundet denne side indtil nu, ville det have været nyttigt, før jeg begyndte mit eventyr. Jeg ønskede at bruge letsencrypt sammen med min dockercontainerside og nginx med så lidt vedligeholdelse som muligt. letsencrypt-certifikater er kun gode i 90 dage.

I min forskning skete jeg med et dockerbillede linuxserver / letsencrypt, der lover at bruge nginx, letsencrypt-certifikatgenerering OG automatisk fornyelse. Lyder fedt! Mens dokumentationen af ​​billedet for det meste virker tilstrækkelig - for en person, der er velbevandret i al denne proces. Jeg fandt det mangler. Hele installationsprocessen tog mig noget tid at finde ud af. Derfor dette indlæg for forhåbentlig at hjælpe den næste person, eller igen mig i fremtiden!

Kampe

De ting, jeg mest kæmpede med, da jeg fik dette linuxserver / letsencrypt-billede til at fungere var:

  • Hvordan "docker" -mængder "fungerer" og deres forhold til denne container
  • Sådan indstilles volumener til at udnytte min konfiguration (relateret til ovenstående punkt) - Jeg havde oprindeligt mange problemer med at finde ud af, hvorfor mine indstillinger, der blev ændret på containeren, blev ændret ved genindlæsning af containeren (for det er det, de er formodes at gøre)
  • Sådan oprettes den korrekte nginx-konfiguration - hvor skal du placere den, og hvad du skal sætte i den.

Docker-diskenheder

Docker-diskenheder (doc):

Volumener er den foretrukne mekanisme til vedvarende data genereret af og brugt af Docker-containere. Mens bindingsbeslag er afhængige af bibliotekstrukturen på værtsmaskinen, styres volumener fuldstændigt af Docker. Volumener har flere fordele i forhold til bindebeslag

letsencrypt har en masse konfiguration til at gå sammen med det. Det tog et stykke tid for mig at indse, men jeg havde brug for en lydstyrke, der blev kortlagt fra en mappe på dockerværten til en bestemt mappe på letsencrypt-billedet. Til sidst opnåede jeg dette i komponentfilen sådan:

volumes: - ${DOCKER_KRITNER_NGINX}:/config - ./nginx.conf:/config/nginx/site-confs/default

Det første element i arrayet ( ${DOCKER_KRITNER_NGINX}:/config) tager en ny miljøvariabel, der kortlægger værtsmappen (defineret i variablen) til /configselve dockercontaineren. Dette betyder, at dockerværten (ved env var-stien) vil indeholde den samme konfiguration som dockerbeholderen i den sekundære del af volumenkortlægningen ( /config)

Det andet element ( ./nginx.conf:/config/nginx/site-confs/default) kortlægger mine lokale arkiver nginx.conf-fil (filen, hvor jeg opretter den omvendte proxy) for at tilsidesætte /config/nginx/site-confs/defaultfilen på docker-værten og containeren.

Den fulde liste over filer, som jeg endte med at skulle ændre til min særlige situation var:

  • /config/dns-conf/dnsimple.ini
  • /config/nginx/site-confs/default

Den dnsimple.inikonfiguration blev tilføje min API-nøgle, og de …/defaulthuser nginx konfiguration.

Den endelige defaultkonfiguration, jeg endte med, er:

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;

Der er et par ændringer fra den standard, der var der, som jeg vil prøve at fremhæve næste.

upstream app_servers { server kritnerwebsite:5000;}

Ovenstående er ret sejt, da docker har sin egen interne DNS (tror jeg?). Du kan oprette en opstrøms server efter containernavnet, i mit tilfælde “kritnerwebsite”. (Bemærk: Jeg ændrede det fra tidligere i indlægget, som var "kritner-website-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 and route53 as per the letsencrypt documentation
  • Staging = true - Jeg brugte dette til at teste alle mine forskellige forsøg inden jeg fik det til at fungere. letsencrypt har hastighedsbegrænsning, når den ikke kører i iscenesættelsestilstand (eller i det mindste i iscenesættelse er det sværere at køre op mod).

Alle ovenstående ændringer, der eksperimenterer, mislykkes og derefter endelig lykkes, kan findes i denne pull-anmodning.

Det endelige resultat?

og fra //www.ssllabs.com/ -

Ikke et “A +”, men virkelig ikke dårligt for at bruge et forudbygget dockerbillede til mine HTTP-behov!

Relaterede:

  • Gå fra et "A" til et "A +" på ssllabs.com