{"id":23592619,"url":"https://github.com/filipnet/letsencrypt-transfer","last_synced_at":"2026-05-09T09:45:32.464Z","repository":{"id":134496107,"uuid":"314483550","full_name":"filipnet/letsencrypt-transfer","owner":"filipnet","description":"Transfer LetsEncrypt certificates from one Linux server to another","archived":false,"fork":false,"pushed_at":"2021-10-27T04:40:46.000Z","size":2,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-27T08:16:11.422Z","etag":null,"topics":["bash","bash-script","certbot","certificate","certificates","letsencrypt","linux","rsync","script","ssh","transfer"],"latest_commit_sha":null,"homepage":"https://www.filipnet.de","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/filipnet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-20T07:52:08.000Z","updated_at":"2022-11-29T11:51:52.000Z","dependencies_parsed_at":"2023-06-16T12:15:14.683Z","dependency_job_id":null,"html_url":"https://github.com/filipnet/letsencrypt-transfer","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filipnet%2Fletsencrypt-transfer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filipnet%2Fletsencrypt-transfer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filipnet%2Fletsencrypt-transfer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filipnet%2Fletsencrypt-transfer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/filipnet","download_url":"https://codeload.github.com/filipnet/letsencrypt-transfer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239432734,"owners_count":19637798,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","bash-script","certbot","certificate","certificates","letsencrypt","linux","rsync","script","ssh","transfer"],"created_at":"2024-12-27T08:14:56.083Z","updated_at":"2026-05-09T09:45:32.454Z","avatar_url":"https://github.com/filipnet.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Let´s Encrypt Compatibility](https://img.shields.io/badge/Let's_Encyrpt-Compatible-brightgreen)\n![Rsync](https://img.shields.io/badge/RSYNC-Required-blue)\n![SSH](https://img.shields.io/badge/SSH-Required-blue)\n\n# Let´s Encrypt Transfer\n\nA robust Bash script to **securely transfer Let's Encrypt certificates** from one Linux server to another using SSH (pull method).  \nIdeal for setups with **load balancers**, **reverse proxies**, or **centralized certificate distribution**.\n\n\u003e ⚠️ **Important Notice**  \n\u003e This script has been **fully refactored and modularized**.  \n\u003e If you used a previous version, **you must now use `.conf` files inside `conf.d/`**. Direct parameter passing is no longer supported.\n\n- [Let´s Encrypt Transfer](#lets-encrypt-transfer)\n  - [Features](#features)\n  - [Installation](#installation)\n  - [Directory Structure](#directory-structure)\n  - [Configuration](#configuration)\n  - [Multiple .conf files supported](#multiple-conf-files-supported)\n    - [Usage](#usage)\n    - [Testing First (Dry Run)](#testing-first-dry-run)\n    - [Automating (cronjob example)](#automating-cronjob-example)\n  - [Why use this script?](#why-use-this-script)\n  - [Requirements](#requirements)\n  - [Sample Output \\\u0026 Logging](#sample-output--logging)\n  - [Security Considerations](#security-considerations)\n  - [Troubleshooting](#troubleshooting)\n  - [Contribution](#contribution)\n  - [License](#license)\n\n\n## Features\n\n- Transfers certificates (`archive`, `live`, `renewal`) over SSH using `rsync`\n- Modular `.conf` based configuration (`conf.d/*.conf`)\n- SSH key-based or password-based authentication\n- Supports non-standard ports and SSH options\n- Default dry-run mode (safe testing)\n- Logging to file and stdout\n- Post-transfer commands (e.g., reload services)\n- Easily cronjob-able\n\n## Installation\n\n```bash\n[ ! -d /opt ] \u0026\u0026 mkdir -p /opt \u0026\u0026 echo \"Created /opt\"\ncd /opt\ngit clone https://github.com/filipnet/letsencrypt-transfer.git\ncd letsencrypt-transfer\nchmod +x letsencrypt-transfer.sh\n```\n\n## Directory Structure\n\n```bash\nletsencrypt-transfer/\n├── letsencrypt-transfer.sh       # Main script\n├── conf.d/                       # Directory for .conf definitions\n│   └── example.conf              # Copy \u0026 customize for each certificate set\n└── .gitignore\n```\n\n## Configuration\n\nCreate one .conf file per certificate/domain in the conf.d/ directory.\nHere is an example:\n\n```ini\n# === Basic Settings ===\n\nSOURCE_HOST=web01.example.com\n\n# Either use:\nSSH_KEY=/root/.ssh/id_rsa_web01\n# Or:\n# SSH_USER=root\n\nSSH_EXTRA_OPTS=\"-4 -p 2222\"\n\nRSYNC_EXTRA_OPTS=\"--compress --numeric-ids --recursive -az\"\n\nARCHIVE_SOURCE=/etc/letsencrypt/archive/webmail.example.com/\nARCHIVE_DEST=/etc/letsencrypt/archive/webmail.example.com/\n\nLIVE_SOURCE=/etc/letsencrypt/live/webmail.example.com/\nLIVE_DEST=/etc/letsencrypt/live/webmail.example.com/\n\nRENEWAL_SOURCE=/etc/letsencrypt/renewal/webmail.example.com.conf\nRENEWAL_DEST=/etc/letsencrypt/renewal/webmail.example.com.conf\n\nDRY_RUN=true\n\nLOGGING_ENABLED=true\nLOG_FILE=/var/log/letsencrypt-transfer.log\n\nPOST_COMMANDS=systemctl reload nginx,systemctl reload dovecot,systemctl reload postfix\n```\n\n## Multiple .conf files supported\n\nThe script will automatically process every file in conf.d/*.conf, skipping example.conf.\n\n### Usage\n\n```bash\n./letsencrypt-transfer.sh\n```\n\nAll matching .conf files in conf.d/ will be processed.\n\nYou will see output in stdout. If logging is enabled, a logfile is also written.\n\n### Testing First (Dry Run)\n\nBy default, `DRY_RUN=true` in your .conf files.\n\nThis will show what would happen without modifying anything.\nSet `DRY_RUN=false` in production.\n\n### Automating (cronjob example)\n\nExample cronjob that runs daily at 4:05 AM:\n\n```cron\n5 4 * * * /opt/letsencrypt-transfer/letsencrypt-transfer.sh \u003e\u003e /dev/null 2\u003e\u00261\n```\n\n## Why use this script?\n\nLet's Encrypt certificates are usually bound to a single machine for issuance (ACME challenge).\n\nIn setups with load balancers or multiple services, you need secure distribution of those certs — and that's exactly what this script does.\n\nNo Docker, no dependencies, just clean rsync and SSH.\n\n## Requirements\n\n- Bash\n- SSH access to the source server\n- rsync installed on both ends\n- Let's Encrypt issued certs on source system\n\n## Sample Output \u0026 Logging\n\nAll script actions are always printed to `stdout`, so you can directly follow what's happening — even when `DRY_RUN=true`.\n\nIf `ENABLE_LOGGING=true` is set in your config file, an additional logfile will be written to the specified `LOG_FILE` path.  \nThis is useful for scheduled or automated runs (e.g., via cron).\n\nWhen ENABLE_LOGGING=true, the same output will be saved to the path defined in LOG_FILE, e.g.: `/var/log/letsencrypt-transfer/mailserver.log`\n\n##  Security Considerations\n\nThis script transfers sensitive Let's Encrypt certificates over SSH. \nMake 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`). \n\nUse SSH key-based authentication where possible, and limit access via firewall rules or SSH configuration. \nLogging is minimal by design and does not include certificate contents. \nAlways test with `DRY_RUN=true` before enabling full sync in production environments.\n\nAvoid exposing SSH directly to the public internet without proper hardening.\n\n---\n\n## Troubleshooting\n\nIf 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.\n\n## Contribution\n\nContributions, ideas, improvements, and bug reports are always welcome!\n\nFeel free to open a [Pull Request](https://github.com/filipnet/letsencrypt-transfer/pulls) or create an [Issue](https://github.com/filipnet/letsencrypt-transfer/issues)  \nto help improve this script for more users.\n\n## License\n\n**letsencrypt-transfer** and all individual scripts are released under the [BSD 3-Clause License](./LICENSE), unless explicitly noted otherwise.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffilipnet%2Fletsencrypt-transfer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffilipnet%2Fletsencrypt-transfer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffilipnet%2Fletsencrypt-transfer/lists"}