dns-lexicon
dns-lexicon is a Python library that provides a standardized and agnostic way to manipulate DNS records across various DNS providers. It abstracts away provider-specific APIs, allowing users to manage DNS records programmatically or via a command-line interface. The library is actively maintained with frequent minor releases, typically on a monthly basis, adding new providers and fixing existing ones. The current version is 3.23.2.
Common errors
-
ClientError: Provider 'non_existent_provider' not found.
cause Attempting to initialize the Client with a provider name that is not recognized or supported by dns-lexicon.fixCheck the spelling of the provider name. Refer to the dns-lexicon documentation or GitHub repository to find the list of supported providers and their exact names (e.g., 'cloudflare', 'godaddy', 'linode4'). -
ClientError: Authentication failed for provider 'myprovider'. Invalid credentials.
cause The credentials (API key, token, user/password) provided in the Client configuration are incorrect, expired, or lack the necessary permissions for the specified DNS provider.fixDouble-check your API credentials against your DNS provider's dashboard. Ensure they are correctly passed in the `config` dictionary and have the required permissions for DNS record management. Also, verify that the correct credential key names are used for your specific provider (e.g., `cloudflare_token`, `godaddy_secret`). -
ValueError: Invalid record type 'TXT' for given content.
cause Attempting to create a DNS record with a type that does not match the provided content, or using a record type not supported by the provider for the given action.fixVerify that the `rtype` (record type, e.g., 'A', 'AAAA', 'CNAME', 'TXT', 'MX') and `content` are consistent and valid according to DNS standards and your provider's API documentation. For instance, an 'A' record needs an IPv4 address, and a 'CNAME' record needs a hostname.
Warnings
- breaking Breaking change in provider names: The `linode` provider was replaced by `linode4` in v3.23.0. While `linode4` is still usable for retro-compatibility, direct usage of `linode` may lead to issues or removal in future versions.
- breaking Python version support has been dropped incrementally. Python 3.9 support was removed in v3.22.0, and Python 3.8 support was removed in v3.19.0. The library now requires Python >= 3.10.
- gotcha Authentication methods and required credentials are highly provider-specific. While `dns-lexicon` standardizes the API calls, the underlying authentication requirements (e.g., API keys, tokens, client IDs/secrets) vary significantly between providers. Consult the `dns-lexicon` documentation for your specific provider.
- gotcha Some DNS providers have strict requirements or limitations on record names (e.g., subdomains), record content (e.g., specific formats for TXT records), or TTL values. Incorrect values might lead to API errors or unexpected behavior.
Install
-
pip install dns-lexicon
Imports
- Client
import dns_lexicon.Client
from lexicon.client import Client
Quickstart
import os
from lexicon.client import Client
# Example for Cloudflare. Replace with your actual provider and credentials.
# Credentials should be stored securely, e.g., in environment variables.
provider_name = 'cloudflare'
domain_name = 'example.com' # Replace with your actual domain
config = {
'provider_name': provider_name,
'domain': domain_name,
'cloudflare_token': os.environ.get('LEXICON_CLOUDFLARE_TOKEN', 'YOUR_CLOUDFLARE_API_TOKEN_HERE')
}
try:
client = Client(config)
print(f"Connected to {provider_name} for domain {domain_name}")
# List all records
records = client.list_records()
print(f"Existing records for {domain_name}:")
for record in records:
print(f" ID: {record['id']}, Name: {record['name']}, Type: {record['type']}, Content: {record['content']}")
# Example: Create a TXT record (uncomment to run)
# record_name = 'test-record'
# record_content = 'This is a test TXT record from dns-lexicon'
# new_record = client.create_record(rtype='TXT', name=record_name, content=record_content)
# print(f"Created TXT record: {new_record['name']} -> {new_record['content']}")
# Example: Delete a record by ID (uncomment and replace with actual ID)
# record_id_to_delete = 'your_record_id_here'
# client.delete_record(identifier=record_id_to_delete)
# print(f"Deleted record with ID: {record_id_to_delete}")
except Exception as e:
print(f"An error occurred: {e}")