This commit is contained in:
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
README.md
|
||||||
|
LICENSE
|
||||||
|
*.md
|
||||||
67
.gitea/workflows/build.yml
Normal file
67
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
name: Build Container
|
||||||
|
run-name: ${{ gitea.actor }} is pushing
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: gitea.haschek.at
|
||||||
|
IMAGE_NAME: ${{ gitea.repository }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo "🎉 Building ${{ gitea.repository }} because of a ${{ gitea.event_name }} event."
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Normalize image name to lowercase
|
||||||
|
run: |
|
||||||
|
echo "IMAGE_NAME_LC=${IMAGE_NAME,,}" >> "$GITHUB_ENV"
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: ${{ env.IMAGE_NAME }}
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
id: prep
|
||||||
|
run: |
|
||||||
|
DOCKER_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LC }}"
|
||||||
|
VERSION=latest
|
||||||
|
SHORTREF=${GITHUB_SHA::8}
|
||||||
|
|
||||||
|
TAGS="${DOCKER_IMAGE}:latest"
|
||||||
|
|
||||||
|
# Set output parameters.
|
||||||
|
echo ::set-output name=tags::${TAGS}
|
||||||
|
echo ::set-output name=docker_image::${DOCKER_IMAGE}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Log in to the Container registry
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ gitea.actor }}
|
||||||
|
password: ${{ secrets.BUILD_TOKEN}}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
env:
|
||||||
|
ACTIONS_RUNTIME_TOKEN: ''
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
context: .
|
||||||
|
file: Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.prep.outputs.tags }}
|
||||||
|
cache-from: |
|
||||||
|
type=registry,ref=registry.haschek.at/${{ env.IMAGE_NAME_LC }}:buildcache
|
||||||
|
cache-to: |
|
||||||
|
type=registry,ref=registry.haschek.at/${{ env.IMAGE_NAME_LC }}:buildcache,mode=max
|
||||||
26
Dockerfile
Normal file
26
Dockerfile
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
LABEL maintainer="Your Name <youremail@example.com>"
|
||||||
|
LABEL description="Certbot with dns-standalone plugin for wildcard certificate generation"
|
||||||
|
|
||||||
|
# Install certbot and the dns-standalone plugin
|
||||||
|
RUN pip install --no-cache-dir certbot certbot-dns-standalone
|
||||||
|
|
||||||
|
# Create directories for Let's Encrypt data
|
||||||
|
RUN mkdir -p /etc/letsencrypt /var/lib/letsencrypt /var/log/letsencrypt
|
||||||
|
|
||||||
|
# Copy the entrypoint script
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
# Expose DNS port (53) for both TCP and UDP
|
||||||
|
EXPOSE 53/tcp
|
||||||
|
EXPOSE 53/udp
|
||||||
|
|
||||||
|
# Expose HTTP port for potential HTTP challenges
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Volume for certificate storage
|
||||||
|
VOLUME ["/etc/letsencrypt", "/var/lib/letsencrypt"]
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
172
README.md
Normal file
172
README.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# DNS Wildcard Certificate Generator
|
||||||
|
|
||||||
|
A Docker container for easily obtaining wildcard SSL certificates from Let's Encrypt using the `certbot-dns-standalone` plugin.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
This uses the `dns-standalone` authenticator which runs its own DNS server to respond to ACME DNS-01 challenges. You need to configure your DNS to delegate `_acme-challenge` queries to this container.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. A server with port 53 (DNS) available
|
||||||
|
2. DNS configuration to route challenge queries to your server (see DNS Setup below)
|
||||||
|
|
||||||
|
## DNS Setup
|
||||||
|
|
||||||
|
### Option 1: Direct NS Record
|
||||||
|
|
||||||
|
Point `_acme-challenge` records to your certbot server using CNAME and NS records:
|
||||||
|
|
||||||
|
```dns
|
||||||
|
; For acme.example.com as your certbot endpoint
|
||||||
|
acme IN NS ns.acme.example.com.
|
||||||
|
ns.acme IN A 1.2.3.4
|
||||||
|
|
||||||
|
; For each domain you want certificates for
|
||||||
|
_acme-challenge.example.com IN CNAME example.com.acme.example.com.
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `1.2.3.4` is the IP of the server running this container.
|
||||||
|
|
||||||
|
### Option 2: DNS Proxy/Forwarding
|
||||||
|
|
||||||
|
If you already run a DNS server, configure it to forward `_acme-challenge` queries to the container.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -it --rm \
|
||||||
|
-v "/etc/letsencrypt:/etc/letsencrypt" \
|
||||||
|
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
|
||||||
|
-p 53:53/tcp -p 53:53/udp \
|
||||||
|
-e EMAIL="youremail@example.com" \
|
||||||
|
-e DOMAINS="-d example.com -d *.example.com" \
|
||||||
|
dns-wildcard-cert
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Locally
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t dns-wildcard-cert .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Required | Default | Description |
|
||||||
|
|----------|----------|---------|-------------|
|
||||||
|
| `EMAIL` | Yes | - | Email for Let's Encrypt registration |
|
||||||
|
| `DOMAINS` | Yes | - | Domain flags (e.g., `-d example.com -d *.example.com`) |
|
||||||
|
| `DNS_ADDRESS` | No | `0.0.0.0` | IPv4 address to bind DNS server |
|
||||||
|
| `DNS_IPV6_ADDRESS` | No | `::` | IPv6 address to bind DNS server |
|
||||||
|
| `DNS_PORT` | No | `53` | Port for DNS server |
|
||||||
|
| `STAGING` | No | `false` | Use Let's Encrypt staging server (for testing) |
|
||||||
|
| `DRY_RUN` | No | `false` | Perform a dry run without saving certificates |
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
**Test with staging server first:**
|
||||||
|
```bash
|
||||||
|
docker run -it --rm \
|
||||||
|
-v "/etc/letsencrypt:/etc/letsencrypt" \
|
||||||
|
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
|
||||||
|
-p 53:53/tcp -p 53:53/udp \
|
||||||
|
-e EMAIL="youremail@example.com" \
|
||||||
|
-e DOMAINS="-d example.com -d *.example.com" \
|
||||||
|
-e STAGING="true" \
|
||||||
|
dns-wildcard-cert
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dry run (no certificates saved):**
|
||||||
|
```bash
|
||||||
|
docker run -it --rm \
|
||||||
|
-p 53:53/tcp -p 53:53/udp \
|
||||||
|
-e EMAIL="youremail@example.com" \
|
||||||
|
-e DOMAINS="-d example.com -d *.example.com" \
|
||||||
|
-e DRY_RUN="true" \
|
||||||
|
dns-wildcard-cert
|
||||||
|
```
|
||||||
|
|
||||||
|
**Bind to specific IP:**
|
||||||
|
```bash
|
||||||
|
docker run -it --rm \
|
||||||
|
-v "/etc/letsencrypt:/etc/letsencrypt" \
|
||||||
|
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
|
||||||
|
-p 1.2.3.4:53:53/tcp -p 1.2.3.4:53:53/udp \
|
||||||
|
-e EMAIL="youremail@example.com" \
|
||||||
|
-e DOMAINS="-d example.com -d *.example.com" \
|
||||||
|
-e DNS_ADDRESS="0.0.0.0" \
|
||||||
|
dns-wildcard-cert
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use non-standard port (with DNS forwarding):**
|
||||||
|
```bash
|
||||||
|
docker run -it --rm \
|
||||||
|
-v "/etc/letsencrypt:/etc/letsencrypt" \
|
||||||
|
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
|
||||||
|
-p 5555:5555/tcp -p 5555:5555/udp \
|
||||||
|
-e EMAIL="youremail@example.com" \
|
||||||
|
-e DOMAINS="-d example.com -d *.example.com" \
|
||||||
|
-e DNS_PORT="5555" \
|
||||||
|
dns-wildcard-cert
|
||||||
|
```
|
||||||
|
|
||||||
|
## Certificate Renewal
|
||||||
|
|
||||||
|
For renewal, you can run the same container periodically or use certbot's renew command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -it --rm \
|
||||||
|
-v "/etc/letsencrypt:/etc/letsencrypt" \
|
||||||
|
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
|
||||||
|
-p 53:53/tcp -p 53:53/udp \
|
||||||
|
--entrypoint certbot \
|
||||||
|
dns-wildcard-cert renew
|
||||||
|
```
|
||||||
|
|
||||||
|
## Certificate Location
|
||||||
|
|
||||||
|
Certificates are stored in the `/etc/letsencrypt` volume:
|
||||||
|
|
||||||
|
- Certificate: `/etc/letsencrypt/live/<domain>/fullchain.pem`
|
||||||
|
- Private Key: `/etc/letsencrypt/live/<domain>/privkey.pem`
|
||||||
|
|
||||||
|
## Docker Compose
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
certbot:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "53:53/tcp"
|
||||||
|
- "53:53/udp"
|
||||||
|
environment:
|
||||||
|
- EMAIL=youremail@example.com
|
||||||
|
- DOMAINS=-d example.com -d *.example.com
|
||||||
|
- STAGING=false
|
||||||
|
volumes:
|
||||||
|
- letsencrypt:/etc/letsencrypt
|
||||||
|
- letsencrypt-lib:/var/lib/letsencrypt
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
letsencrypt:
|
||||||
|
letsencrypt-lib:
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameter Changes
|
||||||
|
|
||||||
|
**Note:** The old certbot-dns-standalone parameter format has changed:
|
||||||
|
|
||||||
|
| Old Format | New Format |
|
||||||
|
|------------|------------|
|
||||||
|
| `--authenticator certbot-dns-standalone:dns-standalone` | `--authenticator dns-standalone` |
|
||||||
|
| `--certbot-dns-standalone:dns-standalone-address=` | `--dns-standalone-address=` |
|
||||||
|
| `--certbot-dns-standalone:dns-standalone-ipv6-address=` | `--dns-standalone-ipv6-address=` |
|
||||||
|
| `--certbot-dns-standalone:dns-standalone-port=` | `--dns-standalone-port=` |
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
21
docker-compose.yml
Normal file
21
docker-compose.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
certbot:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "53:53/tcp"
|
||||||
|
- "53:53/udp"
|
||||||
|
environment:
|
||||||
|
- EMAIL=youremail@example.com
|
||||||
|
- DOMAINS=-d example.com -d *.example.com
|
||||||
|
# Set to true for testing
|
||||||
|
- STAGING=false
|
||||||
|
- DRY_RUN=false
|
||||||
|
volumes:
|
||||||
|
- letsencrypt:/etc/letsencrypt
|
||||||
|
- letsencrypt-lib:/var/lib/letsencrypt
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
letsencrypt:
|
||||||
|
letsencrypt-lib:
|
||||||
47
entrypoint.sh
Normal file
47
entrypoint.sh
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
EMAIL="${EMAIL:-}"
|
||||||
|
DOMAINS="${DOMAINS:-}"
|
||||||
|
DNS_ADDRESS="${DNS_ADDRESS:-0.0.0.0}"
|
||||||
|
DNS_IPV6_ADDRESS="${DNS_IPV6_ADDRESS:-::}"
|
||||||
|
DNS_PORT="${DNS_PORT:-53}"
|
||||||
|
STAGING="${STAGING:-false}"
|
||||||
|
DRY_RUN="${DRY_RUN:-false}"
|
||||||
|
|
||||||
|
# Validate required environment variables
|
||||||
|
if [ -z "$EMAIL" ]; then
|
||||||
|
echo "ERROR: EMAIL environment variable is required"
|
||||||
|
echo "Usage: docker run -e EMAIL=you@example.com -e DOMAINS='-d example.com -d *.example.com' ..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$DOMAINS" ]; then
|
||||||
|
echo "ERROR: DOMAINS environment variable is required"
|
||||||
|
echo "Usage: docker run -e EMAIL=you@example.com -e DOMAINS='-d example.com -d *.example.com' ..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build certbot command
|
||||||
|
CMD="certbot --non-interactive --agree-tos --email ${EMAIL} certonly"
|
||||||
|
CMD="${CMD} --authenticator dns-standalone"
|
||||||
|
CMD="${CMD} --dns-standalone-address=${DNS_ADDRESS}"
|
||||||
|
CMD="${CMD} --dns-standalone-ipv6-address=${DNS_IPV6_ADDRESS}"
|
||||||
|
CMD="${CMD} --dns-standalone-port=${DNS_PORT}"
|
||||||
|
|
||||||
|
# Add staging flag if requested (useful for testing)
|
||||||
|
if [ "$STAGING" = "true" ]; then
|
||||||
|
CMD="${CMD} --staging"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add dry-run flag if requested
|
||||||
|
if [ "$DRY_RUN" = "true" ]; then
|
||||||
|
CMD="${CMD} --dry-run"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add domains
|
||||||
|
CMD="${CMD} ${DOMAINS}"
|
||||||
|
|
||||||
|
echo "Running: ${CMD}"
|
||||||
|
exec ${CMD}
|
||||||
Reference in New Issue
Block a user