Skip to content

Commit 4e32b8c

Browse files
authored
Merge pull request #33 from coderbuzz/feat/cf-proxied-during-cert
fix: create CF DNS record with proxied=false first for Caddy cert issuance
2 parents fdb736c + e8775a5 commit 4e32b8c

3 files changed

Lines changed: 71 additions & 2 deletions

File tree

‎internal/app/repository.go‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,15 @@ func (r *Repository) SaveDNSRecord(appID, serverID int64, zoneID, recordID, name
349349
return err
350350
}
351351

352+
func (r *Repository) UpdateDNSRecordProxied(recordID string, proxied bool) error {
353+
proxiedInt := 0
354+
if proxied {
355+
proxiedInt = 1
356+
}
357+
_, err := r.db.Exec(`UPDATE dns_records SET proxied = ? WHERE record_id = ?`, proxiedInt, recordID)
358+
return err
359+
}
360+
352361
func (r *Repository) GetDNSRecords(appID int64) ([]DNSRecordInfo, error) {
353362
rows, err := r.db.Query(`
354363
SELECT id, app_id, server_id, zone_id, record_id, name, type, content, proxied, created_at

‎internal/app/service.go‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,15 +392,38 @@ func (s *Service) setupRouteAndDNSForDomain(route Route, app *App, svr *server.S
392392
log.Printf("DNS A record already exists for %s, IP matches (IP: %s, proxied: %v)", route.Domain, existing.Content, existing.Proxied)
393393
}
394394
} else {
395-
record, err := s.cf.CreateRecord(route.Domain, svr.Host, true)
395+
record, err := s.cf.CreateRecord(route.Domain, svr.Host, false)
396396
if err != nil {
397397
log.Printf("Warning: Cloudflare DNS failed for %s: %v", route.Domain, err)
398398
if logs != nil {
399399
*logs = append(*logs, fmt.Sprintf("dns/%s: %v", route.Domain, err))
400400
}
401401
} else {
402-
log.Printf("DNS A record created: %s -> %s", record.Name, record.Content)
402+
log.Printf("DNS A record created: %s -> %s (proxied=false)", record.Name, record.Content)
403403
s.repo.SaveDNSRecord(app.ID, svr.ID, record.ZoneID, record.ID, record.Name, "A", record.Content, record.Proxied)
404+
405+
caddyClient := caddy.NewClient(client)
406+
if caddyClient.WaitForCertificate(route.Domain, 60*time.Second) {
407+
updated, err := s.cf.UpdateRecord(record.ID, route.Domain, svr.Host, true)
408+
if err != nil {
409+
log.Printf("Warning: failed to enable Cloudflare proxy for %s: %v", route.Domain, err)
410+
if logs != nil {
411+
*logs = append(*logs, fmt.Sprintf("dns/%s: enable proxy failed: %v", route.Domain, err))
412+
}
413+
} else {
414+
log.Printf("Cloudflare proxy enabled for %s", route.Domain)
415+
s.repo.UpdateDNSRecordProxied(record.ID, true)
416+
if logs != nil {
417+
*logs = append(*logs, fmt.Sprintf("dns/%s: proxy enabled (cert ok)", route.Domain))
418+
}
419+
_ = updated
420+
}
421+
} else {
422+
log.Printf("Timeout waiting for Caddy cert for %s, leaving proxied=false", route.Domain)
423+
if logs != nil {
424+
*logs = append(*logs, fmt.Sprintf("dns/%s: timeout, proxy disabled", route.Domain))
425+
}
426+
}
404427
}
405428
}
406429
}

‎internal/caddy/client.go‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package caddy
33
import (
44
"encoding/json"
55
"fmt"
6+
"strconv"
67
"strings"
8+
"time"
79

810
"github.com/coderbuzz/dockify/internal/ssh"
911
"golang.org/x/crypto/bcrypt"
@@ -143,6 +145,41 @@ func (c *Client) RemoveRoute(domain string) error {
143145
return nil
144146
}
145147

148+
// CheckCertificate checks whether Caddy has obtained a valid TLS certificate
149+
// for the given domain by performing a TLS handshake via localhost.
150+
func (c *Client) CheckCertificate(domain string) (bool, error) {
151+
cmd := fmt.Sprintf(
152+
`docker exec caddy curl -sI -o /dev/null -w '%%{http_code}' --connect-timeout 5 --resolve %s:443:127.0.0.1 https://%s/ 2>&1`,
153+
domain, domain,
154+
)
155+
out, err := c.ssh.Exec(cmd)
156+
if err != nil {
157+
return false, nil
158+
}
159+
code := strings.TrimSpace(out)
160+
if code == "" || code == "000" {
161+
return false, nil
162+
}
163+
n, err := strconv.Atoi(code)
164+
if err != nil || n == 0 {
165+
return false, nil
166+
}
167+
return true, nil
168+
}
169+
170+
// WaitForCertificate polls CheckCertificate until the cert is ready or timeout.
171+
func (c *Client) WaitForCertificate(domain string, timeout time.Duration) bool {
172+
deadline := time.Now().Add(timeout)
173+
for time.Now().Before(deadline) {
174+
ready, err := c.CheckCertificate(domain)
175+
if err == nil && ready {
176+
return true
177+
}
178+
time.Sleep(2 * time.Second)
179+
}
180+
return false
181+
}
182+
146183
func sanitizeID(s string) string {
147184
r := strings.NewReplacer(".", "-", "*", "-")
148185
return "dockify-" + r.Replace(s)

0 commit comments

Comments
 (0)