TLS på en Raspberry Pi med LetsEncrypt och Nginx

Vi har tidigare skrivit om hur marknaden förändras av lättheten att få certifikat via AWS och Letsencrypt.

Under helgen för kristi flygare var jag uppe i min stuga utanför Ånge och satte upp en Raspberry Pi 2 med Z-wave controller för att kunna slå på mina element några dagar innan jag åker upp på vintern.

Jag använde mig av en image från http://razberry.z-wave.me vilket gjorde uppsättningen löjligt enkel. I installationen finns en webserver på port 8083 där man kan styra hela härligheten.

Som ni ser har jag båda elementen påslagna och en ena elementet har dragit 18,3 kWh.

Mitt problem är att jag inte alls litar på den inbyggda webservern och dessutom vill jag naturligtvis köra SSL/TLS så jag installerade nginx som proxy framför den inbyggda webservern. Första steget är att installera nginx:

sudo apt-get update
sudo apt-get install nginx

Det tråkiga är att den senaste versionen via apt-get är 1.6.2 som släpptes 16 September 2014. Så här ser configurationen ut för nginx:

server {
    listen 80 default_server;
    keepalive_timeout 70;
    server_name stugan.allberg.se;
    location / {
        proxy_pass http://localhost:8083;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/stugan.allberg.se/.htpasswd;
        
        add_header X-Frame-Options "deny";
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options "nosniff";
	}
}

Ni ser att jag har satt ett lösenord för att de fula fiskarna på Internet inte ska kunna komma åt webservern på port 8083 och jag har också satt upp lite HTTP headrar för att skydda mig själv.

Men jag vill ju också ha SSL/TLS! Letsencrypt är nu igång på allvar och även om de inte stödjer nginx direkt så fungerar det utmärkt och det är vad jag tänkte visa här.

Först måste vi skapa tillgång till katalogen “/.well-known”, vilket är den katalog där letsencrypt lägger sin challenge. Det gör vi i nginx configuration genom att lägga en location under location:

server {
    listen 80 default_server;
    keepalive_timeout 70;
    server_name stugan.allberg.se;
    location / {
        location /.well-known {
            root /etc/nginx/stugan.allberg.se;
            allow all;
        }
        proxy_pass http://localhost:8083;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/stugan.allberg.se/.htpasswd;
        
        add_header X-Frame-Options "deny";
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options "nosniff";
    }
}

Kom ihåg att ladda om nginx efter configurationen med

sudo nginx -s reload

Lägg nu en fil i katalogen .well-known och använd curl -v för att komma åt den så att du vet att allting fungerar.

Letsencrypt-klienten installeras genom att checka ut den från github:

sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt

Nu ska vi hämta certifikat, vilket vi gör genoma att köra letsencrypt-klienten. Jag har satt root för websiten till /etc/nginx/stugan.allberg.se och den ska skickas med i kommandot till letsencrypt. Parametern -d anger den address som servern har på Internet och kan anges flera gånger, t.ex. med och utan www. I mitt fall har jag bara en adress, stugan.allberg.se.

I vissa fall vill man öka nyckellängden från 2048 till 4096. I mitt fall behöver jag inte det men jag gör det för att jag kan… :-)

cd /opt/letsencrypt
sudo ./letsencrypt-auto certonly -a webroot --rsa-key-size 2048 --webroot-path=/etc/nginx/stugan.allberg.se -d stugan.allberg.se

Om den behöver det så hämtar klienten ned lite paket via apt-get och ett antal Python-paket. I mitt fall tog det sin lilla tid på mobilt bredband i kombination med att Raspberry 2 inte heller är den bästa kompileringsplattformen. :-)

När klienten lyckas fick jag fyra nya filer under /etc/letsencrypt/live/stugan.allberg.se (nåja, egentlige är det länkar till filer som ligger under /etc/letsencrypt/archive):

  • cert.pem: Mitt server-certifikat
  • chain.pem: Let’s Encrypts mellanliggande certifikat
  • fullchain.pem: Kombinationen av cert.pem och chain.pem
  • privkey.pem: Privata nyckeln till ditt server-certifikat

Innan jag konfigurerar nginx behöver jag skapa starka Diffie-Hellman nycklar. Första gången jag gjorde det på min Raspberry höll den på i en timme innan jag avbröt. Nästa gång tog det 10 minuter så räkna med att det kommer att ta tid men avbryt och försök igen om det tar för lång tid. Ett annat sätt är naturligtvis att köra det på en dator med lite mer kräm och sedan kopiera upp den till din Raspberry.

sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096

Nu ska vi konfigurera in allting i nginx. Nu har jag delat på http och https-server så att jag alltid kör en redirect på http till https, men inte om det är till ./well-known. Letsencrypt-klienten kommer nämligen att behöva köras regelbundet för att uppdatera certifikatet.

server {
    listen 80;
    location / {
        location /.well-known {
            root /etc/nginx/stugan.allberg.se;
            allow all;
            auth_basic off;
        }

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

server {
    listen 443 ssl;

    server_name stugan.allberg.se;

    ssl_certificate /etc/letsencrypt/live/stugan.allberg.se/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/stugan.allberg.se/privkey.pem;
    ssl_session_timeout 10m;
    keepalive_timeout 70;

    ssl_dhparam /etc/nginx/ssl/dhparams.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        location /.well-known {
        root /etc/nginx/stugan.allberg.se;
            allow all;
            auth_basic off;
        }

        location ~ ^/(smarthome|ZAutomation) {
            proxy_pass http://127.0.0.1:8083;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;

            auth_basic "Restricted";
            auth_basic_user_file /etc/nginx/stugan.allberg.se/.htpasswd;
        }

        root /etc/nginx/stugan.allberg.se;
        add_header X-Frame-Options "deny";
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options "nosniff";
        add_header Strict-Transport-Security "max-age=16070400;includeSubDomains;";
	}
}

Och på det viset fick jag i alla fall A+ från SSLlabs.


Nästa inlägg ("Elegnämndens federation avstängd") >>
<< Tidigare inlägg ("Lessons Learned From the Swedish Income Tax Return 2016")

Share This:    
John Allberg

John har arbetat med elektronisk identifiering och e-legitimationer sedan 2000. Först på Posten eSäkerhet mellan 2000 och 2004, sedan på Telia mellan 2004 och 2008. Från 2009 är han konsult inom området och 2010 grundade han Ayoy tillsammans med Oscar Jacobsson.