README
¶
libdns-websupport: Websupport DNS Provider (libdns)
This project implements a libdns provider for Websupport DNS.
Implements the libdns interfaces for Websupport's DNS API so you can manage TXT records for ACME DNS-01 and other use cases.
Important: This repo includes a Windows-friendly test app (main.go) that can:
- Create/delete TXT records via Websupport API
- Generate a self‑signed certificate for
libdns.example.comfor local testing - Simulate an ACME DNS‑01 workflow (create/verify/cleanup)
Import path note
You may notice imports like github.com/libdns/websupport/websupport (double websupport).
This is because the provider implementation lives in the websupport/ subdirectory of the repository.
- The module path is
github.com/libdns/websupport(the repository root). - The package that implements the provider is in the
websupportsubfolder, so the full import path becomesgithub.com/libdns/websupport/websupport.
If you prefer a single-segment import (for example github.com/libdns/websupport), we can reorganize the repository so the provider package is at the repository root and move the test application into cmd/ (recommended). Let me know if you want me to do that.
Features
- ACME DNS-01 Support: Solve DNS challenges for Let's Encrypt and other ACME providers
- Full libdns Interface: Implements
RecordAppender,RecordDeleter, andRecordGetterinterfaces - TXT Record Management: Create, retrieve, and delete DNS TXT records
- Basic Authentication: Secure API communication using Websupport API credentials
- Context Support: Full context cancellation support for timeouts and cancellations
Installation
To use this provider in your project, add it as a dependency:
go get github.com/libdns/websupport
Alternatively, clone the repository:
git clone https://github.com/libdns/websupport.git
cd websupport
go mod download
Usage
Basic Setup
package main
import (
"context"
"github.com/libdns/libdns"
"github.com/libdns/websupport/websupport"
"time"
)
func main() {
// Create a provider with your Websupport credentials
// SECURITY: Do NOT hardcode real API keys. Prefer environment variables.
provider := &websupport.Provider{
APIKey: os.Getenv("WEBSUPPORT_API_KEY"),
APISecret: os.Getenv("WEBSUPPORT_API_SECRET"),
APIBase: "https://rest.websupport.sk/v2",
}
ctx := context.Background()
zone := "example.com"
// Create a TXT record for ACME challenge
records := []libdns.Record{
&libdns.TXT{
Name: "_acme-challenge",
Text: "challenge-value",
TTL: 120 * time.Second,
},
}
// Append records
created, err := provider.AppendRecords(ctx, zone, records)
if err != nil {
panic(err)
}
// ... use created records ...
// Delete records when done
deleted, err := provider.DeleteRecords(ctx, zone, created)
if err != nil {
panic(err)
}
}
Configuration
Environment Variables
You can configure the provider using environment variables:
export WEBSUPPORT_API_KEY="your-api-key"
export WEBSUPPORT_API_SECRET="your-api-secret"
export WEBSUPPORT_SERVICE_ID="your-service-id" # Required: Numeric ID for your domain
export WEBSUPPORT_TEST_ZONE="example.com" # Your domain name (not subdomain)
Important Notes:
WEBSUPPORT_TEST_ZONEis your root domain (e.g.,example.com), NOT a subdomainWEBSUPPORT_SERVICE_IDis required - this is the numeric ID for your domain- When creating records for subdomains like
test.example.com, useName: "test"in the record
Why is WEBSUPPORT_SERVICE_ID required?
The Websupport REST API v2 uses service-based endpoints (/v2/service/{id}/dns/record) rather than domain-based endpoints. The API does not provide a working endpoint to automatically discover service IDs from domain names, so you must provide it manually.
How to find your Service ID:
- Log in to Websupport Admin Panel
- Click on your domain from the services list
- Look at the URL in your browser address bar
- The service ID is the number at the end of the URL
Example: https://admin.websupport.sk/en/dashboard/service/1234567 → Service ID is 1234567
Testing the Provider
To test the provider with your credentials:
# Build the project
go build .
# Set environment variables
export WEBSUPPORT_API_KEY="your-api-key"
export WEBSUPPORT_API_SECRET="your-api-secret"
export WEBSUPPORT_SERVICE_ID="your-service-id"
export WEBSUPPORT_TEST_ZONE="your-domain.com"
# Run tests
./libdns-websupport test
Complete test command example:
cd /path/to/websupport && \
go build . && \
export WEBSUPPORT_API_KEY="your-api-key" && \
export WEBSUPPORT_API_SECRET="your-api-secret" && \
export WEBSUPPORT_TEST_ZONE="example.com" && \
export WEBSUPPORT_SERVICE_ID="1234567" && \
./libdns-websupport test
Provider Struct
type Provider struct {
APIKey string // Websupport API Key
APISecret string // Websupport API Secret
APIBase string // API Base URL (default: https://rest.websupport.sk/v2)
ServiceID string // Service ID for the domain (required)
HTTPClient *http.Client // Custom HTTP client (optional)
Timeout time.Duration // Request timeout (default: 30s)
}
API Reference
AppendRecords
Creates DNS records in the zone. Used for adding ACME challenge records.
func (p *Provider) AppendRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error)
- Parameters:
ctx: Context for cancellation and timeoutszone: Domain name (e.g., "example.com")recs: Records to create (typicallylibdns.TXTrecords)
- Returns: Created records with populated IDs and any errors
DeleteRecords
Removes DNS records from the zone by ID.
func (p *Provider) DeleteRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error)
- Parameters:
ctx: Context for cancellation and timeoutszone: Domain namerecs: Records to delete (must have valid IDs from creation)
- Returns: Deleted records and any errors
GetRecords
Retrieves all DNS records from the zone.
func (p *Provider) GetRecords(ctx context.Context, zone string) ([]libdns.Record, error)
- Parameters:
ctx: Context for cancellation and timeoutszone: Domain name
- Returns: All TXT records in the zone and any errors
Examples
Complete ACME Challenge Workflow
package main
import (
"context"
"fmt"
"time"
"github.com/libdns/libdns"
"github.com/libdns/websupport/websupport"
)
func main() {
provider := &websupport.Provider{
APIKey: os.Getenv("WEBSUPPORT_API_KEY"),
APISecret: os.Getenv("WEBSUPPORT_API_SECRET"),
APIBase: "https://rest.websupport.sk/v2",
}
ctx := context.Background()
zone := "example.com"
// Step 1: Create challenge record
challengeRecord := &libdns.TXT{
Name: "_acme-challenge",
Text: "your-challenge-token",
TTL: 120 * time.Second,
}
created, err := provider.AppendRecords(ctx, zone, []libdns.Record{challengeRecord})
if err != nil {
fmt.Printf("Failed to create record: %v\n", err)
return
}
fmt.Printf("Created record: %+v\n", created[0])
// Step 2: Wait for DNS propagation
time.Sleep(5 * time.Second)
// Step 3: Verify record exists
records, err := provider.GetRecords(ctx, zone)
if err != nil {
fmt.Printf("Failed to get records: %v\n", err)
return
}
fmt.Printf("Found %d records\n", len(records))
// Step 4: Clean up
deleted, err := provider.DeleteRecords(ctx, zone, created)
if err != nil {
fmt.Printf("Failed to delete record: %v\n", err)
return
}
fmt.Printf("Deleted %d records\n", len(deleted))
}
Integration with Caddy (example JSON)
This provider can be integrated with Caddy's DNS plugin system via CertMagic:
{
"apps": {
"tls": {
"automation": {
"policies": [
{
"issuers": [
{
"module": "acme",
"challenges": {
"dns": {
"provider": {
"name": "websupport",
"api_key": "${WEBSUPPORT_API_KEY}",
"api_secret": "${WEBSUPPORT_API_SECRET}"
}
}
}
}
]
}
]
}
}
}
}
Testing
The project includes a comprehensive test application that allows you to validate the DNS provider functionality and generate test certificates.
Test Commands
Environment variables used by the test app:
WEBSUPPORT_API_KEY— Your Websupport API key (required)WEBSUPPORT_API_SECRET— Your Websupport API secret (required)WEBSUPPORT_SERVICE_ID— Numeric service ID for your domain (required)WEBSUPPORT_TEST_ZONE— Your root domain (e.g.,example.com) - NOT a subdomainWEBSUPPORT_TEST_DOMAIN— FQDN for cert/tests (default:libdns.example.com)
Important: WEBSUPPORT_TEST_ZONE should be your root domain like example.com, not a subdomain like test.example.com.
The test application supports three commands:
1. Basic DNS Operations Test
Tests creating, retrieving, and deleting DNS records:
Linux/Mac:
export WEBSUPPORT_API_KEY="your-api-key"
export WEBSUPPORT_API_SECRET="your-api-secret"
export WEBSUPPORT_SERVICE_ID="1234567"
export WEBSUPPORT_TEST_ZONE="example.com"
./libdns-websupport test
Windows:
$env:WEBSUPPORT_API_KEY = "your-api-key"
$env:WEBSUPPORT_API_SECRET = "your-api-secret"
$env:WEBSUPPORT_SERVICE_ID = "1234567"
$env:WEBSUPPORT_TEST_ZONE = "example.com"
.\libdns-websupport.exe test
This will:
- Create a test TXT record
- Retrieve all records from your zone
- Delete the test record
- Display success/failure information
2. Create Self-Signed Certificate (Local Testing Only)
Generates a self-signed certificate for local testing purposes. This is NOT a real Let's Encrypt certificate and will show security warnings in browsers.
Linux/Mac:
./libdns-websupport create-cert
Windows:
.\libdns-websupport.exe create-cert
This will:
- Generate a 2048-bit RSA private key
- Create a self-signed certificate (NOT trusted by browsers, for testing only)
- Certificate is valid for 1 year
- Save certificate to:
~/.caddy/certificates/libdns.example.com.crt(Linux/Mac) orC:\Users\<YourUsername>\.caddy\certificates\libdns.example.com.crt(Windows) - Save private key to:
~/.caddy/certificates/libdns.example.com.key(Linux/Mac) orC:\Users\<YourUsername>\.caddy\certificates\libdns.example.com.key(Windows)
Important: This creates a self-signed certificate for testing purposes only. To get real, trusted SSL/TLS certificates, see the "Obtaining Real Let's Encrypt Certificates" section below.
3. ACME DNS-01 Challenge Test (Simulation Only)
Simulates a complete ACME DNS-01 challenge workflow WITHOUT contacting Let's Encrypt. This tests that the DNS provider can create and clean up challenge records correctly.
Linux/Mac:
export WEBSUPPORT_API_KEY="your-api-key"
export WEBSUPPORT_API_SECRET="your-api-secret"
export WEBSUPPORT_SERVICE_ID="1234567"
export WEBSUPPORT_TEST_ZONE="example.com"
./libdns-websupport acme-test
Windows:
$env:WEBSUPPORT_API_KEY = "your-api-key"
$env:WEBSUPPORT_API_SECRET = "your-api-secret"
$env:WEBSUPPORT_SERVICE_ID = "1234567"
$env:WEBSUPPORT_TEST_ZONE = "example.com"
.\libdns-websupport.exe acme-test
This will:
- Create a DNS challenge record (
_acme-challengeTXT record) - Wait for DNS propagation
- Verify the record via public DNS lookup
- Retrieve records from the API
- Clean up the challenge record
Important: This command only simulates the ACME workflow for testing purposes. It does NOT contact Let's Encrypt and does NOT issue a real certificate. See the section below for obtaining real certificates.
Obtaining Real Let's Encrypt Certificates
None of the built-in test commands (test, create-cert, acme-test) obtain real Let's Encrypt certificates. They are only for testing the DNS provider functionality.
To obtain real, trusted SSL/TLS certificates from Let's Encrypt for your domain or subdomains, you need to use this provider with an ACME client.
Recommended ACME Clients
This provider works with any ACME client that supports the libdns interface:
- Caddy - Automatic HTTPS server (easiest option)
- Traefik - Reverse proxy with automatic HTTPS
- Certbot - Official Let's Encrypt client
- acme.sh - Shell script ACME client
- Lego - Go-based ACME client
For Subdomains
When obtaining certificates for subdomains like test.example.com:
- Set
WEBSUPPORT_TEST_ZONEto your root domain (e.g.,example.com) - The ACME challenge will create
_acme-challenge.test.example.comautomatically - The provider will create the TXT record with
Name: "_acme-challenge.test"in your root domain
Example for subdomain certificate:
export WEBSUPPORT_API_KEY="your-api-key"
export WEBSUPPORT_API_SECRET="your-api-secret"
export WEBSUPPORT_SERVICE_ID="1234567"
export WEBSUPPORT_TEST_ZONE="example.com" # Root domain, NOT subdomain
# In your ACME client configuration, request cert for:
# - test.example.com
# - *.example.com (wildcard)
# - example.com (root)
Using with Traefik
Traefik can use this provider for automatic certificate generation. Example configuration:
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: /acme.json
dnsChallenge:
provider: websupport
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
# Environment variables for Traefik:
# WEBSUPPORT_API_KEY=your-api-key
# WEBSUPPORT_API_SECRET=your-api-secret
# WEBSUPPORT_SERVICE_ID=1234567
Using with Caddy
Caddy can automatically obtain certificates using this DNS provider. You'll need to build Caddy with the Websupport DNS module or use the libdns interface directly.
Building from Source
Linux/Mac:
git clone https://github.com/libdns/websupport.git
cd websupport
go build .
Windows:
git clone https://github.com/libdns/websupport.git
cd websupport
go build .
Simulate ACME challenge
.\libdns-websupport.exe acme-test
---
## Testing (Linux)
The test app works the same on Linux. Replace PowerShell with bash and note that files are written to `~/.caddy/certificates`.
### Test Commands
Environment variables used by the test app (optional but recommended):
- `WEBSUPPORT_TEST_ZONE` — your zone (default: `example.com`)
- `WEBSUPPORT_TEST_DOMAIN` — FQDN for cert/tests (default: `libdns.example.com`)
#### 1. Basic DNS Operations Test
```bash
export WEBSUPPORT_API_KEY="your-api-key"
## Task Runners
### Linux/macOS (Makefile)
Common tasks:
```bash
# Build binary
make build
# Run locally
make run
# Run tests
make test
# Create self-signed certificate (writes to ~/.caddy/certificates)
make cert
# DNS operations test (requires API env vars)
make dns-test
# ACME simulation (requires API env vars)
make acme-test
Windows (PowerShell)
Use the provided make.ps1 script:
export WEBSUPPORT_API_SECRET="your-api-secret"
./libdns-websupport test
2. Create Self-Signed Certificate
./libdns-websupport create-cert
ls -l ~/.caddy/certificates/libdns.example.com.*
Expected files:
~/.caddy/certificates/libdns.example.com.crt~/.caddy/certificates/libdns.example.com.key
3. ACME DNS-01 Challenge Test
export WEBSUPPORT_API_KEY="your-api-key"
export WEBSUPPORT_API_SECRET="your-api-secret"
./libdns-websupport acme-test
Building from Source
git clone https://github.com/goozoon/libdns-websupport.git
cd libdns-websupport
go build .
Quick Run
go run .
Development
Project Layout
libdns-websupport/
├── go.mod # Go module definition
├── go.sum # Go module checksums
├── main.go # Test application
├── readme.md # This file
└── websupport/
└── provider.go # libdns provider implementation
Building
go build ./websupport
Quick Run
go run .
Running Tests
go test ./...
Security & Publishing Checklist
- Credentials: Never hardcode API credentials. Use environment variables or a secrets vault.
- HTTPS: All API calls use HTTPS for secure communication
- Basic Auth: Credentials are sent via HTTP Basic Authentication
- Rate Limiting: Be mindful of Websupport's API rate limits when managing records
- GitHub Safety: Before publishing, search the repo for your domain or secrets and remove any accidental commits.
- Local Testing: The
create-certcommand generates a self‑signed cert; do not use it in production.
Resources
License
This project is open source and available under the MIT License.
Contributing
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
Support
For issues, questions, or suggestions, please open an issue on GitHub.
Documentation
¶
There is no documentation for this package.