# How to Configure SSL/TLS Certificates with Let's Encrypt for Self-Hosted Services

> Secure your self-hosted services with free SSL/TLS certificates using Let's Encrypt and Certbot. Learn how to easily configure HTTPS for your domains.

- Repository: [Michael Royal/Self-Hosting-Guide](https://github.com/mikeroyal/Self-Hosting-Guide)
- Tags: how-to-guide
- Published: 2026-06-17

---

**Let's Encrypt provides free, automated X.509 certificates that enable HTTPS for any domain you control using the ACME protocol, typically implemented via Certbot or containerized add-ons.**

The Self-Hosting-Guide repository by mikeroyal references Let's Encrypt as the standard solution for securing self-hosted applications with HTTPS. According to the guide at [`README.md`](https://github.com/mikeroyal/Self-Hosting-Guide/blob/main/README.md) line 2583, you can obtain certificates through either native Certbot clients or Docker-based automation tools that handle the entire certificate lifecycle.

## Two Approaches to Certificate Automation

Self-hosting environments typically use one of two architectures to obtain and manage Let's Encrypt certificates:

- **Certbot (stand-alone or web-server plugin)** – A native client that communicates directly with the Let's Encrypt ACME API. It can spin up a temporary HTTP server for validation or integrate with existing web servers like Apache or Nginx. Use this approach when you control the host OS and can install packages directly.

- **Docker-based Let's Encrypt add-ons** – Pre-built containers that bundle Certbot with reverse-proxy software. These manage certificates inside the container and expose them via bind-mounts or Docker networks. Ideal for container-centric setups where you prefer not to install software on the host.

Both methods rely on the ACME protocol, where Let's Encrypt issues an HTTP-01 challenge that the client must fulfill to prove domain ownership.

## Method 1: Certbot Stand-Alone Installation

### Installation and Initial Certificate Request

To install Certbot on Ubuntu or Debian systems and obtain your first certificate:

```bash
sudo apt update && sudo apt install -y certbot

sudo certbot certonly --standalone \
    -d example.com -d www.example.com \
    --email admin@example.com \
    --agree-tou --no-eff-email

```

The `--standalone` flag instructs Certbot to spin up a temporary web server on port 80 to complete the HTTP-01 challenge. This requires port 80 to be accessible from the internet without NAT hairpinning.

### Web Server Configuration

After obtaining the certificate, configure your web server to use the generated files. For Nginx, create a configuration file that references the certificate paths:

```bash
cat <<'EOF' | sudo tee /etc/nginx/sites-available/example.com.conf
server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # ... your location blocks ...

}
EOF

sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

```

### Automatic Renewal Setup

Certbot installations include a systemd timer that handles renewal automatically. Enable and start this timer to ensure certificates renew every 60 days (certificates are valid for 90 days):

```bash
sudo systemctl enable --now certbot.timer

```

This timer runs `certbot renew` daily and reloads your web server when certificates are refreshed.

## Method 2: Docker-Based Let's Encrypt Add-ons

For container-centric deployments, use a Docker-based approach like the Home Assistant Let's Encrypt add-on referenced in the Self-Hosting-Guide. This method bundles the certificate management with your reverse proxy.

### Docker Compose Configuration

Create a [`docker-compose.yml`](https://github.com/mikeroyal/Self-Hosting-Guide/blob/main/docker-compose.yml) that runs Certbot alongside an Nginx reverse proxy:

```yaml
version: "3.8"
services:
  nginx-proxy:
    image: nginxproxy/nginx-proxy:latest
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./letsencrypt:/etc/nginx/certs:ro
    restart: unless-stopped

  letsencrypt:
    image: linuxserver/letsencrypt
    container_name: letsencrypt
    environment:
      - URL=example.com
      - VALIDATION=http
      - EMAIL=admin@example.com
    volumes:
      - ./letsencrypt:/config
    network_mode: "service:nginx-proxy"
    restart: unless-stopped

```

The `linuxserver/letsencrypt` container runs Certbot internally and shares network space with the reverse proxy to answer challenges. Certificates are written to `./letsencrypt` and mounted read-only into the proxy.

### Volume Mounting and Proxy Integration

The container stores certificates in a persistent volume that your application containers can access via bind-mounts. When the certificate renews, the container automatically reloads the proxy to apply the new certificate without manual intervention.

## Method 3: Caddy with Built-In ACME Support

Caddy includes a native ACME client that eliminates manual configuration. Create a `Caddyfile`:

```caddyfile
example.com {
    reverse_proxy your_service:8080
    tls admin@example.com
}

```

Deploy with Docker:

```bash
docker run -d -p 80:80 -p 443:443 \
  -v $(pwd)/Caddyfile:/etc/caddy/Caddyfile \
  -v caddy_data:/data caddy:latest

```

Caddy automatically obtains and renews certificates, handling the HTTP-01 challenge internally and reloading the configuration when certificates update.

## ACME Protocol and Validation Requirements

Regardless of the method chosen, several requirements must be met for successful certificate issuance:

- **Domain resolution** must point to your public IP address before initiating the challenge.
- **Port 80/443 accessibility** is required for the HTTP-01 challenge; ensure your firewall and router allow inbound connections.
- **Private key security** is critical; restrict `privkey.pem` permissions to only the process that needs it (typically `chmod 600`).
- **Automatic renewal** occurs every 60 days by default, ensuring continuous HTTPS availability without manual intervention.

## Summary

- **Let's Encrypt** provides free SSL/TLS certificates through the automated ACME protocol.
- **Certbot** offers a native solution for Linux hosts with systemd-based renewal timers.
- **Docker add-ons** like `linuxserver/letsencrypt` provide containerized certificate management for microservice architectures.
- **Caddy** offers zero-configuration HTTPS with built-in ACME support.
- **Port 80 must be open** to the internet for HTTP-01 validation to succeed.
- **Automatic renewal** is standard across all methods, ensuring certificates never expire unexpectedly.

## Frequently Asked Questions

### What is the difference between Certbot stand-alone and web-server plugin modes?

Certbot stand-alone mode spins up a temporary web server on port 80 to complete the ACME challenge, while plugin mode uses your existing Apache or Nginx installation to answer challenges. Use stand-alone when no web server is running, and use plugin mode when you already have a web server installed that you want to configure automatically.

### Can I use Let's Encrypt with a dynamic IP address?

Yes, but you must configure a dynamic DNS provider like DuckDNS to keep your domain pointing at your current public IP. The Self-Hosting-Guide indicates that Docker-based Let's Encrypt add-ons can be coupled with dynamic DNS providers to maintain certificate validity even when your IP changes.

### How do I troubleshoot certificate renewal failures?

First verify that port 80 is accessible from the internet and that your domain DNS records resolve to your current public IP. Check Certbot logs with `sudo journalctl -u certbot` or examine the Docker container logs for ACME error messages. Ensure no firewall rules block inbound connections during the challenge window.

### Where are the certificate files stored in a Docker-based setup?

Docker-based Let's Encrypt containers typically store certificates in a bind-mounted volume such as `./letsencrypt` or `/config` within the container. These volumes map to host directories containing `fullchain.pem` and `privkey.pem` files that you can mount into other containers or reference directly in your reverse-proxy configuration.