<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Acel</title>
    <description>The latest articles on DEV Community by Acel (@acel).</description>
    <link>https://dev.to/acel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F435788%2F4a741b7f-8630-4fde-9bad-a4d86a08fac7.jpeg</url>
      <title>DEV Community: Acel</title>
      <link>https://dev.to/acel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/acel"/>
    <language>en</language>
    <item>
      <title>How to Get Free SSL Certificates with Docker &amp; LetsEncrypt</title>
      <dc:creator>Acel</dc:creator>
      <pubDate>Tue, 23 Jul 2024 20:44:05 +0000</pubDate>
      <link>https://dev.to/mlasunilag/how-to-get-free-ssl-certificates-with-docker-letsencrypt-7ml</link>
      <guid>https://dev.to/mlasunilag/how-to-get-free-ssl-certificates-with-docker-letsencrypt-7ml</guid>
      <description>&lt;p&gt;"An SSL certificate is a digital certificate that authenticates a website's identity and enables an encrypted connection. SSL stands for Secure Sockets Layer, a security protocol that creates an encrypted link between a web server and a web browser." - kaspersky&lt;/p&gt;

&lt;p&gt;Majority of websites built today use SSL certificates, and if you are building a website in 2024, you will need to learn how to get one too!&lt;/p&gt;

&lt;p&gt;There are several approaches to getting an SSL certificate for your domain. But in this article, we will take a look at generating SSL certificates with &lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;Let's Encrypt&lt;/a&gt; - a nonprofit certificate authority (CA) that provides free SSL/TLS certificates for enabling HTTPS (secure HTTP) on websites. In addition to this, automating the renewal process with &lt;a href="https://certbot.eff.org/" rel="noopener noreferrer"&gt;Certbot&lt;/a&gt; and using a Docker image that was built on top of the official Nginx Docker images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To successfully complete this guide, you should be familiar with the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker and Docker Compose&lt;/li&gt;
&lt;li&gt;Virtual machines from cloud providers, e.g. Azure VMs, AWS EC2 etc.&lt;/li&gt;
&lt;li&gt;Linux&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a good idea to containerize your app with Docker, but if you don't want to, you can still follow along just fine!&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Certbot and Nginx
&lt;/h2&gt;

&lt;p&gt;In the root directory of your project, please create a docker-compose file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then paste the following code in the docker-compose.yml file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jonasal/nginx-certbot:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CERTBOT_EMAIL&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx-certbot.env&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;80:80&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;443:443&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nginx_secrets:/etc/letsencrypt&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./user_conf.d:/etc/nginx/user_conf.d&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nginx_secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code we just pasted above is a YAML configuration for our Nginx docker image. It makes use of the &lt;code&gt;jonasal/nginx-certbot:latest&lt;/code&gt; image that has certbot built on top of Nginx.&lt;/p&gt;

&lt;p&gt;Now, let us create a &lt;code&gt;nginx-certbot.env&lt;/code&gt; file to store the variables needed for our Nginx image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;nginx-certbot.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then paste this into your &lt;code&gt;nginx-certbot.env&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Required
CERTBOT_EMAIL=your@email.com

# Optional (Defaults)
DHPARAM_SIZE=2048
RSA_KEY_SIZE=2048
ELLIPTIC_CURVE=secp256r1
RENEWAL_INTERVAL=8d
USE_ECDSA=1
STAGING=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create a server configuration file to configure our Nginx server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;server.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    # Listen to port 443 on both IPv4 and IPv6.
    listen 443 ssl default_server reuseport;
    listen [::]:443 ssl default_server reuseport;

    # Domain names this server should respond to.
    server_name yourdomain.com www.yourdomain.com;

    # Load the certificate files.
    ssl_certificate         /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;

    # Load the Diffie-Hellman parameter.
    ssl_dhparam /etc/letsencrypt/dhparams/dhparam.pem;

    # Redirect non-https traffic to https
    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }

    return 200 'Let\'s Encrypt certificate successfully installed!';
    add_header Content-Type text/plain;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, all we need to do is build the docker image and run it on our server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, move the images to the server whose IP address is mapped to a domain name you own and run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command starts the server and Certbot automatically creates new SSL certificates for us. Try navigating to the domain name mapped to the server, you should see a "not trusted" page.&lt;/p&gt;

&lt;p&gt;This is because we used "test" certificates to make sure that our configuration works fine. Issuing of live certificates is rate limited, so using test/staging certificates first is a better approach to ensure that it runs fine.&lt;/p&gt;

&lt;p&gt;Now, we will update our &lt;code&gt;nginx-certbot.env&lt;/code&gt; file to enable us generate live SSL certificates. Change the staging value from 1 to 0.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
STAGING=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop the server with ctrl+c and run the command below to regenerate SSL certificates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;container_name&amp;gt; /scripts/run_certbot.sh force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start up the server again&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, navigate to your domain name. Your site should open up just fine!&lt;/p&gt;

&lt;h2&gt;
  
  
  Certbot and Nginx configurations for Dockerized apps
&lt;/h2&gt;

&lt;p&gt;Assuming you dockerized your app, you will need to make a few more changes to what we have done so far.&lt;br&gt;
First, we update the docker-compose.yml file so that the Nginx service depends on your app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ...
    volumes:
      - nginx_secrets:/etc/letsencrypt
      - ./user_conf.d:/etc/nginx/user_conf.d
    depends_on:
      - web

  web:
    container_name: core_app
    build: .
    restart: always
    ...

volumes:
  nginx_secrets:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;web&lt;/code&gt; is the name of your app service.&lt;/p&gt;

&lt;p&gt;Then, we update the &lt;code&gt;server.conf&lt;/code&gt; file to point to our web server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;upstream webapp {
    server core_app:8000;
    # core_app is the container name of the web server
    # 8000 is the port for the web container
}
server {
    # Listen to port 443 on both IPv4 and IPv6.
    listen 443 ssl default_server reuseport;
    listen [::]:443 ssl default_server reuseport;

    # Domain names this server should respond to.
    server_name yourdomain.com www.yourdomain.com;

    server_tokens off;
    client_max_body_size 20M;

    # Load the certificate files.
    ssl_certificate         /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;

    # Load the Diffie-Hellman parameter.
    ssl_dhparam /etc/letsencrypt/dhparams/dhparam.pem;

    # Redirect non-https traffic to https
    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }

    location / {
        proxy_pass http://webapp;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, Nginx should be routing traffic directly to your web server (docker container).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We have successfully created free SSL certificates for our domain name that renew automatically, so we never have to worry about it unless our server goes down.&lt;/p&gt;

&lt;p&gt;In addition to this article, you can learn more about this approach here: &lt;a href="https://github.com/JonasAlfredsson/docker-nginx-certbot/tree/master" rel="noopener noreferrer"&gt;https://github.com/JonasAlfredsson/docker-nginx-certbot/tree/master&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;p&gt;¡Hasta luego!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
