Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mguptahub committed Oct 26, 2024
0 parents commit 533268b
Show file tree
Hide file tree
Showing 19 changed files with 1,426 additions and 0 deletions.
122 changes: 122 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: Build

on:
workflow_dispatch:
push:
tags: [ 'v*' ]
# branches: [ "master" ]
# pull_request:
# branches: [ "master" ]

permissions:
contents: write
packages: write

env:
GO_VERSION: '1.22'

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: true

- name: Install dependencies
run: go mod download

- name: Run tests with coverage
run: go test -cover ./...

- name: Build
run: go build -v -o nanodns ./cmd/server

docker:
needs: build
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
steps:
- uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,format=long
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Make package public
run: |
PACKAGE_NAME=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')
curl -L \
-X PUT \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/orgs/${{ github.repository_owner }}/packages/container/${PACKAGE_NAME}/visibility \
-d '{"visibility":"public"}'
release:
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION}}
cache: true

- name: Build Release Binaries
run: |
GOOS=linux GOARCH=amd64 go build -o nanodns-linux-amd64 ./cmd/server
GOOS=linux GOARCH=arm64 go build -o nanodns-linux-arm64 ./cmd/server
GOOS=darwin GOARCH=amd64 go build -o nanodns-darwin-amd64 ./cmd/server
GOOS=darwin GOARCH=arm64 go build -o nanodns-darwin-arm64 ./cmd/server
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
nanodns-linux-amd64
nanodns-linux-arm64
nanodns-darwin-amd64
nanodns-darwin-arm64
scripts/install.sh
scripts/uninstall.sh
generate_release_notes: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nanodns
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Build stage
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux go build -o nanodns ./cmd/server

# Final stage
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/nanodns .
EXPOSE 53/udp
CMD ["./nanodns"]
186 changes: 186 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# Nano DNS Server

A lightweight DNS server designed for Docker Compose environments, allowing dynamic resolution of service names and custom DNS records.

## Features

- Environment variable-based configuration
- Support for A, CNAME, MX, and TXT records
- Docker service name resolution
- Optional TTL configuration (default: 60 seconds)
- Lightweight and fast
- Configurable port

## Installation

### Download

Download the latest release from the [releases page](https://github.com/mguptahub/nanodns/releases).

### Platform-specific Instructions

#### Linux Service Installation

Release assets include scripts for installing/uninstalling NanoDNS as a system service:

```bash
# Make scripts executable
chmod +x install.sh uninstall.sh

# Install service
sudo ./install.sh

# View status and logs
systemctl status nanodns
journalctl -u nanodns -f

# Edit configuration
sudo nano /etc/nanodns/nanodns.env

# Uninstall service
sudo ./uninstall.sh
```

#### macOS

If you see the warning "Apple could not verify this app", run these commands:

```bash
# Remove quarantine attribute
xattr -d com.apple.quarantine nanodns-darwin-arm64

# Make executable
chmod +x nanodns-darwin-arm64

# Run the binary
./nanodns-darwin-arm64
```

## Configuration

### Environment Variables

| Variable | Description | Default | Example |
|----------|-------------|---------|---------|
| DNS_PORT | UDP port for DNS server | 53 | 5353 |
| A_xxx | A Record Details | - | - |
| CNAME_xxx | CNAME Record Details | - | - |
| MX_xxx | MX Record Details | - | - |
| TXT_xxx | TXT Record Details | - | - |

### Record Format

All records use the `|` character as a separator. The general format is:
```
RECORD_TYPE_NUMBER=domain|value[|ttl]
```

### A Records
```
A_REC1=domain|ip|ttl
A_REC2=domain|service:servicename|ttl
```
Example:
```
A_REC1=app.example.com|192.168.1.10|300
A_REC2=api.example.com|service:webapp
```

### CNAME Records
```
CNAME_REC1=domain|target|ttl
```
Example:
```
CNAME_REC1=www.example.com|app.example.com|3600
```

### MX Records
```
MX_REC1=domain|priority|mailserver|ttl
```
Example:
```
MX_REC1=example.com|10|mail1.example.com|3600
MX_REC2=example.com|20|mail2.example.com
```

### TXT Records
```
TXT_REC1=domain|"text value"|ttl
```
Example:
```
TXT_REC1=example.com|v=spf1 include:_spf.example.com ~all|3600
TXT_REC2=_dmarc.example.com|v=DMARC1; p=reject; rua=mailto:dmarc@example.com
```

## Docker Compose Usage

```yaml
name: nanodns
services:
dns:
build: .
environment:
- DNS_PORT=5353 # Optional, defaults to 53
# A Records
- A_REC1=app.example.com|service:webapp
- A_REC2=api.example.com|192.168.1.10|300
# TXT Records
- TXT_REC1=example.com|v=spf1 include:_spf.example.com ~all
ports:
- "${DNS_PORT:-5353}:${DNS_PORT:-5353}/udp" # Uses DNS_PORT if set, otherwise 5353
networks:
- app_network

networks:
app_network:
driver: bridge
```
## Running Without Docker Compose
```bash
# Set environment variables
export DNS_PORT=5353
export A_REC1=app.example.com|192.168.1.10
export TXT_REC1=example.com|v=spf1 include:_spf.example.com ~all

# Run the server
./nanodns
```

## Testing Records

```bash
# Test using custom port
dig @localhost -p 5353 app.example.com A

# Test CNAME record
dig @localhost -p 5353 www.example.com CNAME

# Test MX record
dig @localhost -p 5353 example.com MX

# Test TXT record
dig @localhost -p 5353 example.com TXT
```

## Common Issues and Solutions

1. Port 53 already in use (common on macOS and Linux):
- Use a different port by setting `DNS_PORT=5353` or another available port
- Update your client configurations to use the custom port

2. Permission denied when using port 53:
- Use a port number above 1024 to avoid requiring root privileges
- Set `DNS_PORT=5353` or another high-numbered port

## Development

```bash
# Build the server
go build -o nanodns cmd/server/main.go

```
32 changes: 32 additions & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"log"

"github.com/mguptahub/nanodns/internal/dns"
"github.com/mguptahub/nanodns/pkg/config"
externaldns "github.com/miekg/dns"
)

func main() {
// Load records from environment variables
records := dns.LoadRecords()

// Create DNS handler
handler := dns.NewHandler(records)
externaldns.HandleFunc(".", handler.ServeDNS)

// Configure server
port := config.GetDNSPort()
server := &externaldns.Server{
Addr: ":" + port,
Net: "udp",
}

log.Printf("Starting DNS server on port %s", port)
if err := server.ListenAndServe(); err != nil {
log.Fatalf("Failed to start server: %v", err)
}

defer server.Shutdown()
}
14 changes: 14 additions & 0 deletions cmd/server/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"testing"
)

func TestMainPackage(t *testing.T) {
// This is a placeholder test to ensure the main package can be built
// Real integration tests would be more appropriate here
t.Run("main package exists", func(t *testing.T) {
// Simply verify the package can be imported and built
// The actual server functionality should be tested through integration tests
})
}
Loading

0 comments on commit 533268b

Please sign in to comment.