An open API service indexing awesome lists of open source software.

https://github.com/filipnet/letsencrypt-transfer

Transfer LetsEncrypt certificates from one Linux server to another
https://github.com/filipnet/letsencrypt-transfer

bash bash-script certbot certificate certificates letsencrypt linux rsync script ssh transfer

Last synced: about 1 month ago
JSON representation

Transfer LetsEncrypt certificates from one Linux server to another

Awesome Lists containing this project

README

          

![Let´s Encrypt Compatibility](https://img.shields.io/badge/Let's_Encyrpt-Compatible-brightgreen)
![Rsync](https://img.shields.io/badge/RSYNC-Required-blue)
![SSH](https://img.shields.io/badge/SSH-Required-blue)

# Let´s Encrypt Transfer

A robust Bash script to **securely transfer Let's Encrypt certificates** from one Linux server to another using SSH (pull method).
Ideal for setups with **load balancers**, **reverse proxies**, or **centralized certificate distribution**.

> ⚠️ **Important Notice**
> This script has been **fully refactored and modularized**.
> If you used a previous version, **you must now use `.conf` files inside `conf.d/`**. Direct parameter passing is no longer supported.

- [Let´s Encrypt Transfer](#lets-encrypt-transfer)
- [Features](#features)
- [Installation](#installation)
- [Directory Structure](#directory-structure)
- [Configuration](#configuration)
- [Multiple .conf files supported](#multiple-conf-files-supported)
- [Usage](#usage)
- [Testing First (Dry Run)](#testing-first-dry-run)
- [Automating (cronjob example)](#automating-cronjob-example)
- [Why use this script?](#why-use-this-script)
- [Requirements](#requirements)
- [Sample Output \& Logging](#sample-output--logging)
- [Security Considerations](#security-considerations)
- [Troubleshooting](#troubleshooting)
- [Contribution](#contribution)
- [License](#license)

## Features

- Transfers certificates (`archive`, `live`, `renewal`) over SSH using `rsync`
- Modular `.conf` based configuration (`conf.d/*.conf`)
- SSH key-based or password-based authentication
- Supports non-standard ports and SSH options
- Default dry-run mode (safe testing)
- Logging to file and stdout
- Post-transfer commands (e.g., reload services)
- Easily cronjob-able

## Installation

```bash
[ ! -d /opt ] && mkdir -p /opt && echo "Created /opt"
cd /opt
git clone https://github.com/filipnet/letsencrypt-transfer.git
cd letsencrypt-transfer
chmod +x letsencrypt-transfer.sh
```

## Directory Structure

```bash
letsencrypt-transfer/
├── letsencrypt-transfer.sh # Main script
├── conf.d/ # Directory for .conf definitions
│ └── example.conf # Copy & customize for each certificate set
└── .gitignore
```

## Configuration

Create one .conf file per certificate/domain in the conf.d/ directory.
Here is an example:

```ini
# === Basic Settings ===

SOURCE_HOST=web01.example.com

# Either use:
SSH_KEY=/root/.ssh/id_rsa_web01
# Or:
# SSH_USER=root

SSH_EXTRA_OPTS="-4 -p 2222"

RSYNC_EXTRA_OPTS="--compress --numeric-ids --recursive -az"

ARCHIVE_SOURCE=/etc/letsencrypt/archive/webmail.example.com/
ARCHIVE_DEST=/etc/letsencrypt/archive/webmail.example.com/

LIVE_SOURCE=/etc/letsencrypt/live/webmail.example.com/
LIVE_DEST=/etc/letsencrypt/live/webmail.example.com/

RENEWAL_SOURCE=/etc/letsencrypt/renewal/webmail.example.com.conf
RENEWAL_DEST=/etc/letsencrypt/renewal/webmail.example.com.conf

DRY_RUN=true

LOGGING_ENABLED=true
LOG_FILE=/var/log/letsencrypt-transfer.log

POST_COMMANDS=systemctl reload nginx,systemctl reload dovecot,systemctl reload postfix
```

## Multiple .conf files supported

The script will automatically process every file in conf.d/*.conf, skipping example.conf.

### Usage

```bash
./letsencrypt-transfer.sh
```

All matching .conf files in conf.d/ will be processed.

You will see output in stdout. If logging is enabled, a logfile is also written.

### Testing First (Dry Run)

By default, `DRY_RUN=true` in your .conf files.

This will show what would happen without modifying anything.
Set `DRY_RUN=false` in production.

### Automating (cronjob example)

Example cronjob that runs daily at 4:05 AM:

```cron
5 4 * * * /opt/letsencrypt-transfer/letsencrypt-transfer.sh >> /dev/null 2>&1
```

## Why use this script?

Let's Encrypt certificates are usually bound to a single machine for issuance (ACME challenge).

In setups with load balancers or multiple services, you need secure distribution of those certs — and that's exactly what this script does.

No Docker, no dependencies, just clean rsync and SSH.

## Requirements

- Bash
- SSH access to the source server
- rsync installed on both ends
- Let's Encrypt issued certs on source system

## Sample Output & Logging

All script actions are always printed to `stdout`, so you can directly follow what's happening — even when `DRY_RUN=true`.

If `ENABLE_LOGGING=true` is set in your config file, an additional logfile will be written to the specified `LOG_FILE` path.
This is useful for scheduled or automated runs (e.g., via cron).

When ENABLE_LOGGING=true, the same output will be saved to the path defined in LOG_FILE, e.g.: `/var/log/letsencrypt-transfer/mailserver.log`

## Security Considerations

This script transfers sensitive Let's Encrypt certificates over SSH.
Make sure only privileged users (e.g. `root`) execute the script, and that private keys and certificate files are stored securely with restrictive permissions (`chmod 600`).

Use SSH key-based authentication where possible, and limit access via firewall rules or SSH configuration.
Logging is minimal by design and does not include certificate contents.
Always test with `DRY_RUN=true` before enabling full sync in production environments.

Avoid exposing SSH directly to the public internet without proper hardening.

---

## Troubleshooting

If you encounter problems while using this tool (especially with SSH or rsync), please refer to the [HELP.md](./HELP.md) guide for solutions and best practices.

## Contribution

Contributions, ideas, improvements, and bug reports are always welcome!

Feel free to open a [Pull Request](https://github.com/filipnet/letsencrypt-transfer/pulls) or create an [Issue](https://github.com/filipnet/letsencrypt-transfer/issues)
to help improve this script for more users.

## License

**letsencrypt-transfer** and all individual scripts are released under the [BSD 3-Clause License](./LICENSE), unless explicitly noted otherwise.