Let’s Encrypt Certificate Authority (CA) provides free TLS/SSL certificates to enable encrypted HTTPS on web servers. This guide walks you through obtaining a free SSL certificate and configuring it for a Jenkins installation behind an NGINX reverse proxy on Ubuntu.

Table of Contents

  1. Prerequisites
  2. Installing Let’s Encrypt Client
  3. Installing NGINX
  4. Domain Validation Setup
  5. Creating Certification Configuration
  6. Requesting the Certificate
  7. Configuring Jenkins with Reverse Proxy
  8. Auto-Renewal Configuration

Prerequisites

Before you begin, ensure you have the following:

  • A server running Ubuntu 16.04 (or later) with root access.
  • A Fully Qualified Domain Name (FQDN) pointing to your server’s IP address (e.g., jenkins.your-domain.com).
  • Port 80 and 443 open on your firewall.

Installing Let’s Encrypt Client

First, we need to clone the Let’s Encrypt client (Certbot) from GitHub. Ensure git is installed:

sudo apt-get update && sudo apt-get install git -y

Now, clone the repository to the /opt directory:

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


Installing NGINX

We will use NGINX as a reverse proxy. This allows NGINX to handle the SSL termination and forward traffic to Jenkins running on its default port (8080).

sudo apt-get install nginx -y


Domain Validation Setup

Let’s Encrypt needs to validate that you own the domain. We will use the Webroot plugin, which requires placing a temporary file in a specific directory on your server.

Edit the default NGINX configuration: sudo vim /etc/nginx/sites-available/default

Add the following location block to handle the ACME challenge. Replace jenkins.your-domain.com with your actual domain:

server {
  listen 80;
  server_name jenkins.your-domain.com;

  location '/.well-known/acme-challenge' {
    default_type "text/plain";
    root      /var/www/letsencrypt;
    allow all;
  }
}

Verify and reload NGINX: sudo nginx -t && sudo nginx -s reload


Creating Certification Configuration

Instead of passing many arguments to the command line, we’ll create a configuration file. Create a directory for configs if it doesn’t exist: sudo mkdir -p /etc/letsencrypt/configs

Create the config file /etc/letsencrypt/configs/your-domain.conf. Update the domains and email fields:

# Generate certificates for the specified domains.
domains = your-fully-qualified-domain

# Use a strong 4096-bit RSA key
rsa-key-size = 4096

# Email for renewal reminders
email = [email protected]

# Use the webroot authenticator.
authenticator = webroot

# Path served by NGINX for validation
webroot-path = /var/www/letsencrypt/

Requesting the Certificate

Run the Let’s Encrypt client to generate your certificates:

cd /opt/letsencrypt sudo ./letsencrypt-auto --config /etc/letsencrypt/configs/your-domain.conf certonly

Upon success, your certificates will be stored in /etc/letsencrypt/live/your-domain/.


Configuring Jenkins with Reverse Proxy

1. Install Jenkins (Optional)

If you haven’t installed Jenkins yet:

wget -q -O - https://jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo apt-get update && sudo apt-get install jenkins -y

2. Update NGINX Config

Now, configure NGINX to redirect all traffic to HTTPS and proxy it to Jenkins. Update /etc/nginx/sites-available/default:

upstream jenkins {
  server 127.0.0.1:8080 fail_timeout=0;
}

server {
  listen 80;
  server_name jenkins.your-domain.com;

  # Redirect all HTTP traffic to HTTPS
  location / {
    return 301 https://$host$request_uri;
  }

  location '/.well-known/acme-challenge' {
    default_type "text/plain";
    root      /var/www/letsencrypt;
    allow all;
  }
}

server {
  listen 443 ssl;
  server_name jenkins.your-domain.com;

  ssl_certificate /etc/letsencrypt/live/jenkins.your-domain.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/jenkins.your-domain.com/privkey.pem;

  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_prefer_server_ciphers on;
  ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384';

  location / {
    proxy_set_header        Host $host:$server_port;
    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;
    proxy_redirect http:// https://;
    proxy_pass              http://jenkins;
  }
}

Test and restart NGINX: sudo nginx -t && sudo systemctl restart nginx


Auto-Renewal Configuration

Let’s Encrypt certificates expire every 90 days. We can automate renewal with a simple cron job.

Create /etc/cron.monthly/renew-ssl.sh and make it executable: sudo chmod +x /etc/cron.monthly/renew-ssl.sh

#!/bin/bash
cd /opt/letsencrypt/
./letsencrypt-auto --config /etc/letsencrypt/configs/your-domain.conf certonly

if [ $? -eq 0 ]
then
    systemctl reload nginx
else
    echo "SSL Renewal failed!" | mail -s "Alert: Jenkins SSL Renewal" [email protected]
fi

Congratulations! Your Jenkins instance is now secured with a free, auto-renewing SSL certificate.