Skip to content

Commit

Permalink
feat: add support for porkbun
Browse files Browse the repository at this point in the history
  • Loading branch information
davidramiro committed Feb 21, 2023
1 parent 2ba8b75 commit a005486
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 56 deletions.
2 changes: 1 addition & 1 deletion .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project_name: fritzgandi
project_name: frigabun
before:
hooks:
- go mod tidy
Expand Down
61 changes: 41 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
# FritzGandi DynDNS Update
# frigabun

Web service to allow FritzBox routers to update Gandi DNS entries when obtaining a new IP address.
Web service to allow FritzBox routers to update Gandi and Porkbun DNS entries when obtaining a new IP address.
Uses the new LiveDNS API. Written in Go 1.20

## Requirements
- A domain name on Gandi
- Gandi API Key from [Account settings](https://account.gandi.net/) under Security
- A domain name on Gandi or Porkbun
- Gandi or Porkbun API credentials from [Account settings](https://account.gandi.net/) under Security
- FritzBox router with up-to-date firmware
- Optional: To build or run manually: Go 1.20

## Usage
## Set up service

- Download the [latest](https://github.com/davidramiro/fritzgandi/releases/latest) release archive for your OS/arch
- Download the [latest](https://github.com/davidramiro/frigabun/releases/latest) release archive for your OS/arch
- Unzip, rename `config.sample.yml` to `config.yml` (config is fine as default, if you want to run tests, fill in your API info)

## FritzBox settings

- Log into your FritzBox
- Navigate to `Internet` -> `Permit Access` -> `DynDNS`
- Enable DynDNS and use `User-defined` as Provider

### Gandi

- Enter the following URL: `http://{HOST}:{PORT}/api/update?apikey=<passwd>&domain={DOMAIN}&subdomain={SUBDOMAIN}&ip=<ipaddr>`
- Replace the `{HOST}` and `{PORT}` with your deployment of the application
- By default, the application uses port `9595`
Expand All @@ -29,6 +35,21 @@ Uses the new LiveDNS API. Written in Go 1.20
- Unused, but required by the FritzBox interface
- Enter your Gandi API-Key in the `Password` field

### Porkbun

- Enter the following URL: `http://{HOST}:{PORT}/api/update?apikey=<username>&secretapikey=<passwd>&domain={DOMAIN}&subdomain={SUBDOMAIN}&ip=<ipaddr>&registrar=porkbun`
- Replace the `{HOST}` and `{PORT}` with your deployment of the application
- By default, the application uses port `9595`
- Replace `{DOMAIN}` with your base domain
- e.g. `yourdomain.com`
- Replace `{SUBDOMAIN}` with your subdomain or comma separated subdomains
- e.g. `subdomain` or `sudomain1,subdomain2`
- Enter the full domain in the `Domain Name` field
- e.g. `subdomain.domain.com` (if you use multiple subdomains, just choose any of those)
- Enter your Porkbun API key in the `Username` field
- Enter your Porkbun API Secret Key in the `Password` field


Your settings should look something like this:

![](https://kore.cc/fritzgandi/fbsettings.png "FritzBox DynDNS Settings")
Expand All @@ -47,16 +68,16 @@ Check below for an example on how to reverse proxy to this application with NGIN
## Linux systemd Service

To create a systemd service and run the application on boot, create a service file, for example under
`/etc/systemd/system/fritzgandi.service`.
`/etc/systemd/system/frigabun.service`.

Service file contents:
```
[Unit]
Description=FritzGandi LiveDNS Microservice
[Service]
WorkingDirectory=/your/path
ExecStart=/your/path/fritzgandi
WorkingDirectory=/path/to/frigabun
ExecStart=/path/to/frigabun/executable
User=youruser
Type=simple
Restart=on-failure
Expand All @@ -72,13 +93,13 @@ Reload daemon, start the service, check its status:

```
sudo systemctl daemon-reload
sudo systemctl start fritzgandi.service
sudo systemctl status fritzgandi
sudo systemctl start frigabun.service
sudo systemctl status frigabun
```

If all is well, enable the service to be started on boot:

`sudo systemctl enable fritzgandi`
`sudo systemctl enable frigabun`

## NGINX Reverse Proxy

Expand All @@ -89,12 +110,12 @@ Shown below is an example of an NGINX + LetsEncrypt reverse proxy config for thi
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name fritzgandi.yourdomain.com;
server_name frigabun.yourdomain.com;
# SSL
ssl_certificate /etc/letsencrypt/live/fritzgandi.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/fritzgandi.yourdomain.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/fritzgandi.yourdomain.com/chain.pem;
ssl_certificate /etc/letsencrypt/live/frigabun.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/frigabun.yourdomain.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/frigabun.yourdomain.com/chain.pem;
# security headers
add_header X-Frame-Options "DENY";
Expand All @@ -112,8 +133,8 @@ server {
}
# logging
access_log /var/log/nginx/fritzgandi.yourdomain.com.access.log;
error_log /var/log/nginx/fritzgandi.yourdomain.com.error.log warn;
access_log /var/log/nginx/frigabun.yourdomain.com.access.log;
error_log /var/log/nginx/frigabun.yourdomain.com.error.log warn;
# reverse proxy
location / {
Expand Down Expand Up @@ -142,15 +163,15 @@ server {
server {
listen 80;
listen [::]:80;
server_name fritzgandi.yourdomain.com;
server_name frigabun.yourdomain.com;
# ACME-challenge
location ^~ /.well-known/acme-challenge/ {
root /var/www/_letsencrypt;
}
location / {
return 301 https://fritzgandi.yourdomain.com$request_uri;
return 301 https://frigabun.yourdomain.com$request_uri;
}
}
```
3 changes: 3 additions & 0 deletions config.sample.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
gandi:
baseurl: https://dns.api.gandi.net/api/v5
ttl: 300
porkbun:
baseurl: https://porkbun.com/api/json/v3
ttl: 600
api:
port: 9595
hideApiKeyInLogs: true
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/davidramiro/fritzgandi
module github.com/davidramiro/frigabun

go 1.20

Expand Down
48 changes: 36 additions & 12 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
"strings"

"github.com/asaskevich/govalidator"
"github.com/davidramiro/fritzgandi/internal/logger"
"github.com/davidramiro/fritzgandi/pkg/gandi"
"github.com/davidramiro/frigabun/internal/logger"
"github.com/davidramiro/frigabun/pkg/gandi"
"github.com/davidramiro/frigabun/pkg/porkbun"
"github.com/labstack/echo/v4"
)

Expand All @@ -20,8 +21,17 @@ type ApiError struct {
Message string
}

type UpdateRequest struct {
Domain string `query:"domain"`
Subdomains string `query:"subdomain"`
IP string `query:"ip"`
ApiKey string `query:"apikey"`
ApiSecretKey string `query:"apisecretkey"`
Registrar string `query:"registrar"`
}

func HandleUpdateRequest(c echo.Context) error {
var request gandi.UpdateRequest
var request UpdateRequest

err := c.Bind(&request)
if err != nil {
Expand All @@ -45,15 +55,29 @@ func HandleUpdateRequest(c echo.Context) error {
}

for i := range subdomains {
dnsInfo := &gandi.GandiDnsInfo{
IP: request.IP,
Domain: request.Domain,
Subdomain: subdomains[i],
ApiKey: request.ApiKey,
}
err := gandi.AddRecord(dnsInfo)
if err != nil {
return c.String(err.Code, err.Message)
if request.Registrar == "gandi" {
dnsInfo := &gandi.GandiDnsInfo{
IP: request.IP,
Domain: request.Domain,
Subdomain: subdomains[i],
ApiKey: request.ApiKey,
}
err := gandi.AddRecord(dnsInfo)
if err != nil {
return c.String(err.Code, err.Message)
}
} else if request.Registrar == "porkbun" {
dnsInfo := &porkbun.PorkbunDnsInfo{
IP: request.IP,
Domain: request.Domain,
Subdomain: subdomains[i],
ApiKey: request.ApiKey,
SecretApiKey: request.ApiSecretKey,
}
err := porkbun.AddRecord(dnsInfo)
if err != nil {
return c.String(err.Code, err.Message)
}
}

successfulUpdates++
Expand Down
4 changes: 2 additions & 2 deletions internal/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"runtime"
"testing"

"github.com/davidramiro/fritzgandi/internal/config"
"github.com/davidramiro/frigabun/internal/config"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -64,7 +64,7 @@ func TestUpdateEndpointWithValidRequest(t *testing.T) {
q := make(url.Values)
q.Set("ip", config.AppConfig.Test.IP)
q.Set("domain", config.AppConfig.Test.Domain)
q.Set("subdomain", config.AppConfig.Test.Subdomain)
q.Set("subdomain", config.AppConfig.Test.Subdomain+"2")
q.Set("apiKey", config.AppConfig.Test.ApiKey)

e := echo.New()
Expand Down
5 changes: 5 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ type Config struct {
TTL int `yaml:"ttl"`
} `yaml:"gandi"`

Porkbun struct {
BaseUrl string `yaml:"baseurl"`
TTL int `yaml:"ttl"`
} `yaml:"porkbun"`

Api struct {
Port string `yaml:"port"`
ApiKeyHidden bool `yaml:"hideApiKeyInLogs"`
Expand Down
6 changes: 3 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"regexp"
"strings"

"github.com/davidramiro/fritzgandi/internal/api"
"github.com/davidramiro/fritzgandi/internal/config"
"github.com/davidramiro/fritzgandi/internal/logger"
"github.com/davidramiro/frigabun/internal/api"
"github.com/davidramiro/frigabun/internal/config"
"github.com/davidramiro/frigabun/internal/logger"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
Expand Down
2 changes: 1 addition & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"testing"

"github.com/davidramiro/fritzgandi/internal/config"
"github.com/davidramiro/frigabun/internal/config"
"github.com/stretchr/testify/assert"
)

Expand Down
18 changes: 3 additions & 15 deletions pkg/gandi/gandi.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@ import (
"io"
"net/http"

"github.com/davidramiro/fritzgandi/internal/config"
"github.com/davidramiro/fritzgandi/internal/logger"
"github.com/labstack/echo/v4"
"github.com/davidramiro/frigabun/internal/config"
"github.com/davidramiro/frigabun/internal/logger"
)

type UpdateRequest struct {
Domain string `query:"domain"`
Subdomains string `query:"subdomain"`
IP string `query:"ip"`
ApiKey string `query:"apikey"`
}

type GandiDnsInfo struct {
IP string
Domain string
Expand Down Expand Up @@ -77,13 +69,9 @@ func AddRecord(updateRequest *GandiDnsInfo) *GandiUpdateError {

if resp.StatusCode != 201 {
b, _ := io.ReadAll(resp.Body)
logger.Log.Error().Err(err).Msg("gandi rejected request")
logger.Log.Error().Msg("gandi rejected request")
return &GandiUpdateError{Code: resp.StatusCode, Message: "gandi rejected request: " + string(b)}
}

return nil
}

func Hello(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
}
2 changes: 1 addition & 1 deletion pkg/gandi/gandi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"runtime"
"testing"

"github.com/davidramiro/fritzgandi/internal/config"
"github.com/davidramiro/frigabun/internal/config"
"github.com/stretchr/testify/assert"
)

Expand Down
Loading

0 comments on commit a005486

Please sign in to comment.