Skip to content

Instantly share code, notes, and snippets.

@wwin3286tw
Last active August 29, 2023 03:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wwin3286tw/dfe01df469013b91213fa33740794ad9 to your computer and use it in GitHub Desktop.
Save wwin3286tw/dfe01df469013b91213fa33740794ad9 to your computer and use it in GitHub Desktop.
namecheap certbot --manual-auth-hook script

Namecheap DNS-01 Certbot Hook (Modified)

This is a manual authentication hook for Certbot that is specifically designed for DNS-01 validation and integration with Namecheap. This project has been modified and extended based on trwnh/namecheap. Additionally, this new version of the code has been generated after communicating the requirements with ChatGPT.

New Features

Automated polling of DNS TXT records through dns.resolver, eliminating the need to wait for a specific length of time. The script proceeds to the next step as soon as it verifies the record correctly.

Requirements

  • Python 3
  • Requests
  • BeautifulSoup
  • lxml
  • dns.resolver
  • Certbot
  • Namecheap API Key

Current Limitations

  • Please make sure that your username/API KEY/CLIENT IP key is configured within the code.

How to Use

If You Already Have an Existing Certificate

  • Edit your existing renewal configuration file, typically found at /etc/letsencrypt/renewal/your_domain.com.conf, and ensure that it includes the following settings:
[renewalparams]
account = YOUR_ACCOUNT_ID
authenticator = manual
server = https://acme-v02.api.letsencrypt.org/directory
pref_challs = dns-01,
manual_auth_hook = /path/to/this/script
manual_public_ip_logging_ok = True

If You Are Creating a New Certificate, Run the following command:

sudo certbot certonly \
     --preferred-challenges=dns \
     --manual \
     --manual-auth-hook=/path/to/this/script \
     --agree-tos \
     -d your_domain.com,*.your_domain.com
     # You can also consider using the --dry-run parameter to not consume actual quota.
  • Renewal Certificate You should be able to run certbot renew afterward, and the settings will be remembered for future renewals.

Acknowledgments

  • Original Author: trwnh/namecheap
  • ChatGPT for code modifications and README guidance.

Collaboration and Issues

If you have any questions or ideas related to this project, please feel free to share them with me. Make appropriate modifications according to your needs. Hope this is helpful!

License

This project is licensed under the GNU Affero General Public License v3.0.

#!/usr/bin/python3
import requests
import socket
import dns.resolver
from bs4 import BeautifulSoup as bs
import os
import time
SANDBOX = False
# In general: api_username is consistent with nc_username
# 一般來說:api_username 與 nc_username 一致
api_username = "[USERNAME]"
api_key = "[API KEY]"
client_ip = "0.0.0.0"
nc_username = "[USERNAME]"
def main():
domain = os.getenv('CERTBOT_DOMAIN')
validation = os.getenv('CERTBOT_VALIDATION')
records = get_host_records(domain)
if records is None:
print("Failed to get host records.")
return
records = clean_old_challenges(records)
records = append_challenge_tag(records)
set_host_records(domain, records)
if wait_for_dns_propagation("_acme-challenge." + domain, validation):
print("DNS propagation completed.")
else:
print("DNS propagation failed.")
def wait_for_dns_propagation(domain, expected_validation, max_attempts=30, sleep_interval=10):
attempts = 0
while attempts < max_attempts:
try:
answers = dns.resolver.resolve(domain, 'TXT')
for rdata in answers:
if expected_validation in rdata.strings[0].decode('utf-8'):
return True
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
pass
except dns.exception.Timeout:
pass
attempts += 1
time.sleep(sleep_interval)
return False
def method_url(cmd_name, *args, **kwargs):
global api_username, api_key, nc_username, client_ip
sandbox = kwargs.get('sandbox', SANDBOX)
api_url = "https://api.sandbox.namecheap.com/xml.response" if sandbox else "https://api.namecheap.com/xml.response"
return f"{api_url}?ApiUser={api_username}&ApiKey={api_key}&UserName={nc_username}&ClientIp={client_ip}&Command={cmd_name}"
def get_host_records(domain):
url = method_url("namecheap.domains.dns.getHosts")
parts = domain.split('.')
SLD, TLD = parts[-2], parts[-1]
url += f"&SLD={SLD}&TLD={TLD}"
result = requests.get(url).text
soup = bs(result, 'lxml')
hosts = soup.find_all('host')
return [{'name': host['name'], 'type': host['type'], 'address': host['address'], 'ttl': host.get('ttl', None)} for host in hosts]
def clean_old_challenges(records):
return [record for record in records if record['name'] != "_acme-challenge"]
def append_challenge_tag(records):
challenge = os.getenv('CERTBOT_VALIDATION')
challenge_tag = {'name': '_acme-challenge', 'type': 'TXT', 'address': challenge, 'ttl': '60'}
records.append(challenge_tag)
return records
def set_host_records(domain, records):
url = method_url("namecheap.domains.dns.setHosts")
parts = domain.split('.')
SLD, TLD = parts[-2], parts[-1]
url += f"&SLD={SLD}&TLD={TLD}"
for n, record in enumerate(records, 1):
name = record['name']
type = record['type']
address = record['address']
ttl = record.get('ttl', None)
url += f"&HostName{n}={name}&RecordType{n}={type}&Address{n}={address}"
if ttl:
url += f"&TTL{n}={ttl}"
result = requests.get(url).text
soup = bs(result, 'lxml')
success = soup.find_all(attrs={"issuccess": "true"})
if success:
print("Records successfully updated.")
else:
print("Failed to update records.")
if __name__ == "__main__":
main()

Namecheap DNS-01 Certbot Hook (Modified)

這是一個用於DNS-01驗證與Namecheap整合的Certbot手動認證掛鉤。本項目基於trwnh/namecheap進行了修改和擴展。此外,這個版本的代碼是在使用ChatGPT與使用者溝通需求之後所產生的新版本。

新增的特點

透過dns.resolver自動輪尋DNS TXT記錄,不必等待特定時間長度。

要求

  • Python 3
  • Requests
  • BeautifulSoup
  • lxml
  • dns.resolver
  • Certbot
  • Namecheap API 密鑰

當前的局限

  • 請確保自己的使用者名稱/API密鑰/client IP已在程式碼中設定。

使用方法

如果您已有現有的憑證

  • 編輯目前的憑證更新設定文件,例如 /etc/letsencrypt/renewal/your_domain.com.conf,並確保以下設定:
[renewalparams]
account = YOUR_ACCOUNT_ID
authenticator = manual
server = https://acme-v02.api.letsencrypt.org/directory
pref_challs = dns-01,
manual_auth_hook = /path/to/this/script
manual_public_ip_logging_ok = True
  • 如果您正在建立一個新的憑證,請執行以下命令:
sudo certbot certonly \
     --preferred-challenges=dns \
     --manual \
     --manual-auth-hook=/path/to/this/script \
     --agree-tos \
     -d your_domain.com,*.your_domain.com
     # 您還可以考慮使用 --dry-run 參數,不耗用實際配額。

維護

您應該能夠在此之後運行certbot renew,並且設置將被記住。

致謝

  • 原作者:trwnh/namecheap
  • ChatGPT for code modification and README guidance.

協作與問題

如果您有任何與這個項目相關的問題或想法,請隨時與我分享。 請根據您的需求進行適當的修改。希望這對您有幫助!

授權

本項目採用 GNU Affero General Public License v3.0 進行授權。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment