Skip to content

Commit a005486

Browse files
committed
feat: add support for porkbun
1 parent 2ba8b75 commit a005486

File tree

12 files changed

+218
-56
lines changed

12 files changed

+218
-56
lines changed

.goreleaser.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
project_name: fritzgandi
1+
project_name: frigabun
22
before:
33
hooks:
44
- go mod tidy

README.md

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
1-
# FritzGandi DynDNS Update
1+
# frigabun
22

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

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

12-
## Usage
12+
## Set up service
1313

14-
- Download the [latest](https://github.com/davidramiro/fritzgandi/releases/latest) release archive for your OS/arch
14+
- Download the [latest](https://github.com/davidramiro/frigabun/releases/latest) release archive for your OS/arch
1515
- Unzip, rename `config.sample.yml` to `config.yml` (config is fine as default, if you want to run tests, fill in your API info)
16+
17+
## FritzBox settings
18+
1619
- Log into your FritzBox
1720
- Navigate to `Internet` -> `Permit Access` -> `DynDNS`
1821
- Enable DynDNS and use `User-defined` as Provider
22+
23+
### Gandi
24+
1925
- Enter the following URL: `http://{HOST}:{PORT}/api/update?apikey=<passwd>&domain={DOMAIN}&subdomain={SUBDOMAIN}&ip=<ipaddr>`
2026
- Replace the `{HOST}` and `{PORT}` with your deployment of the application
2127
- By default, the application uses port `9595`
@@ -29,6 +35,21 @@ Uses the new LiveDNS API. Written in Go 1.20
2935
- Unused, but required by the FritzBox interface
3036
- Enter your Gandi API-Key in the `Password` field
3137

38+
### Porkbun
39+
40+
- Enter the following URL: `http://{HOST}:{PORT}/api/update?apikey=<username>&secretapikey=<passwd>&domain={DOMAIN}&subdomain={SUBDOMAIN}&ip=<ipaddr>&registrar=porkbun`
41+
- Replace the `{HOST}` and `{PORT}` with your deployment of the application
42+
- By default, the application uses port `9595`
43+
- Replace `{DOMAIN}` with your base domain
44+
- e.g. `yourdomain.com`
45+
- Replace `{SUBDOMAIN}` with your subdomain or comma separated subdomains
46+
- e.g. `subdomain` or `sudomain1,subdomain2`
47+
- Enter the full domain in the `Domain Name` field
48+
- e.g. `subdomain.domain.com` (if you use multiple subdomains, just choose any of those)
49+
- Enter your Porkbun API key in the `Username` field
50+
- Enter your Porkbun API Secret Key in the `Password` field
51+
52+
3253
Your settings should look something like this:
3354

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

4970
To create a systemd service and run the application on boot, create a service file, for example under
50-
`/etc/systemd/system/fritzgandi.service`.
71+
`/etc/systemd/system/frigabun.service`.
5172

5273
Service file contents:
5374
```
5475
[Unit]
5576
Description=FritzGandi LiveDNS Microservice
5677
5778
[Service]
58-
WorkingDirectory=/your/path
59-
ExecStart=/your/path/fritzgandi
79+
WorkingDirectory=/path/to/frigabun
80+
ExecStart=/path/to/frigabun/executable
6081
User=youruser
6182
Type=simple
6283
Restart=on-failure
@@ -72,13 +93,13 @@ Reload daemon, start the service, check its status:
7293

7394
```
7495
sudo systemctl daemon-reload
75-
sudo systemctl start fritzgandi.service
76-
sudo systemctl status fritzgandi
96+
sudo systemctl start frigabun.service
97+
sudo systemctl status frigabun
7798
```
7899

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

81-
`sudo systemctl enable fritzgandi`
102+
`sudo systemctl enable frigabun`
82103

83104
## NGINX Reverse Proxy
84105

@@ -89,12 +110,12 @@ Shown below is an example of an NGINX + LetsEncrypt reverse proxy config for thi
89110
server {
90111
listen 443 ssl http2;
91112
listen [::]:443 ssl http2;
92-
server_name fritzgandi.yourdomain.com;
113+
server_name frigabun.yourdomain.com;
93114
94115
# SSL
95-
ssl_certificate /etc/letsencrypt/live/fritzgandi.yourdomain.com/fullchain.pem;
96-
ssl_certificate_key /etc/letsencrypt/live/fritzgandi.yourdomain.com/privkey.pem;
97-
ssl_trusted_certificate /etc/letsencrypt/live/fritzgandi.yourdomain.com/chain.pem;
116+
ssl_certificate /etc/letsencrypt/live/frigabun.yourdomain.com/fullchain.pem;
117+
ssl_certificate_key /etc/letsencrypt/live/frigabun.yourdomain.com/privkey.pem;
118+
ssl_trusted_certificate /etc/letsencrypt/live/frigabun.yourdomain.com/chain.pem;
98119
99120
# security headers
100121
add_header X-Frame-Options "DENY";
@@ -112,8 +133,8 @@ server {
112133
}
113134
114135
# logging
115-
access_log /var/log/nginx/fritzgandi.yourdomain.com.access.log;
116-
error_log /var/log/nginx/fritzgandi.yourdomain.com.error.log warn;
136+
access_log /var/log/nginx/frigabun.yourdomain.com.access.log;
137+
error_log /var/log/nginx/frigabun.yourdomain.com.error.log warn;
117138
118139
# reverse proxy
119140
location / {
@@ -142,15 +163,15 @@ server {
142163
server {
143164
listen 80;
144165
listen [::]:80;
145-
server_name fritzgandi.yourdomain.com;
166+
server_name frigabun.yourdomain.com;
146167
147168
# ACME-challenge
148169
location ^~ /.well-known/acme-challenge/ {
149170
root /var/www/_letsencrypt;
150171
}
151172
152173
location / {
153-
return 301 https://fritzgandi.yourdomain.com$request_uri;
174+
return 301 https://frigabun.yourdomain.com$request_uri;
154175
}
155176
}
156177
```

config.sample.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
gandi:
22
baseurl: https://dns.api.gandi.net/api/v5
33
ttl: 300
4+
porkbun:
5+
baseurl: https://porkbun.com/api/json/v3
6+
ttl: 600
47
api:
58
port: 9595
69
hideApiKeyInLogs: true

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module github.com/davidramiro/fritzgandi
1+
module github.com/davidramiro/frigabun
22

33
go 1.20
44

internal/api/api.go

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import (
66
"strings"
77

88
"github.com/asaskevich/govalidator"
9-
"github.com/davidramiro/fritzgandi/internal/logger"
10-
"github.com/davidramiro/fritzgandi/pkg/gandi"
9+
"github.com/davidramiro/frigabun/internal/logger"
10+
"github.com/davidramiro/frigabun/pkg/gandi"
11+
"github.com/davidramiro/frigabun/pkg/porkbun"
1112
"github.com/labstack/echo/v4"
1213
)
1314

@@ -20,8 +21,17 @@ type ApiError struct {
2021
Message string
2122
}
2223

24+
type UpdateRequest struct {
25+
Domain string `query:"domain"`
26+
Subdomains string `query:"subdomain"`
27+
IP string `query:"ip"`
28+
ApiKey string `query:"apikey"`
29+
ApiSecretKey string `query:"apisecretkey"`
30+
Registrar string `query:"registrar"`
31+
}
32+
2333
func HandleUpdateRequest(c echo.Context) error {
24-
var request gandi.UpdateRequest
34+
var request UpdateRequest
2535

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

4757
for i := range subdomains {
48-
dnsInfo := &gandi.GandiDnsInfo{
49-
IP: request.IP,
50-
Domain: request.Domain,
51-
Subdomain: subdomains[i],
52-
ApiKey: request.ApiKey,
53-
}
54-
err := gandi.AddRecord(dnsInfo)
55-
if err != nil {
56-
return c.String(err.Code, err.Message)
58+
if request.Registrar == "gandi" {
59+
dnsInfo := &gandi.GandiDnsInfo{
60+
IP: request.IP,
61+
Domain: request.Domain,
62+
Subdomain: subdomains[i],
63+
ApiKey: request.ApiKey,
64+
}
65+
err := gandi.AddRecord(dnsInfo)
66+
if err != nil {
67+
return c.String(err.Code, err.Message)
68+
}
69+
} else if request.Registrar == "porkbun" {
70+
dnsInfo := &porkbun.PorkbunDnsInfo{
71+
IP: request.IP,
72+
Domain: request.Domain,
73+
Subdomain: subdomains[i],
74+
ApiKey: request.ApiKey,
75+
SecretApiKey: request.ApiSecretKey,
76+
}
77+
err := porkbun.AddRecord(dnsInfo)
78+
if err != nil {
79+
return c.String(err.Code, err.Message)
80+
}
5781
}
5882

5983
successfulUpdates++

internal/api/api_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"runtime"
1111
"testing"
1212

13-
"github.com/davidramiro/fritzgandi/internal/config"
13+
"github.com/davidramiro/frigabun/internal/config"
1414
"github.com/labstack/echo/v4"
1515
"github.com/stretchr/testify/assert"
1616
)
@@ -64,7 +64,7 @@ func TestUpdateEndpointWithValidRequest(t *testing.T) {
6464
q := make(url.Values)
6565
q.Set("ip", config.AppConfig.Test.IP)
6666
q.Set("domain", config.AppConfig.Test.Domain)
67-
q.Set("subdomain", config.AppConfig.Test.Subdomain)
67+
q.Set("subdomain", config.AppConfig.Test.Subdomain+"2")
6868
q.Set("apiKey", config.AppConfig.Test.ApiKey)
6969

7070
e := echo.New()

internal/config/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ type Config struct {
1515
TTL int `yaml:"ttl"`
1616
} `yaml:"gandi"`
1717

18+
Porkbun struct {
19+
BaseUrl string `yaml:"baseurl"`
20+
TTL int `yaml:"ttl"`
21+
} `yaml:"porkbun"`
22+
1823
Api struct {
1924
Port string `yaml:"port"`
2025
ApiKeyHidden bool `yaml:"hideApiKeyInLogs"`

main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import (
44
"regexp"
55
"strings"
66

7-
"github.com/davidramiro/fritzgandi/internal/api"
8-
"github.com/davidramiro/fritzgandi/internal/config"
9-
"github.com/davidramiro/fritzgandi/internal/logger"
7+
"github.com/davidramiro/frigabun/internal/api"
8+
"github.com/davidramiro/frigabun/internal/config"
9+
"github.com/davidramiro/frigabun/internal/logger"
1010
"github.com/labstack/echo/v4"
1111
"github.com/labstack/echo/v4/middleware"
1212
)

main_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package main
33
import (
44
"testing"
55

6-
"github.com/davidramiro/fritzgandi/internal/config"
6+
"github.com/davidramiro/frigabun/internal/config"
77
"github.com/stretchr/testify/assert"
88
)
99

pkg/gandi/gandi.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,10 @@ import (
77
"io"
88
"net/http"
99

10-
"github.com/davidramiro/fritzgandi/internal/config"
11-
"github.com/davidramiro/fritzgandi/internal/logger"
12-
"github.com/labstack/echo/v4"
10+
"github.com/davidramiro/frigabun/internal/config"
11+
"github.com/davidramiro/frigabun/internal/logger"
1312
)
1413

15-
type UpdateRequest struct {
16-
Domain string `query:"domain"`
17-
Subdomains string `query:"subdomain"`
18-
IP string `query:"ip"`
19-
ApiKey string `query:"apikey"`
20-
}
21-
2214
type GandiDnsInfo struct {
2315
IP string
2416
Domain string
@@ -77,13 +69,9 @@ func AddRecord(updateRequest *GandiDnsInfo) *GandiUpdateError {
7769

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

8476
return nil
8577
}
86-
87-
func Hello(c echo.Context) error {
88-
return c.String(http.StatusOK, "Hello, World!")
89-
}

0 commit comments

Comments
 (0)