快轉到主要內容

pdns-server 安裝

·6562 字·14 分鐘·
PolloChang
作者
PolloChang
我是一隻雞

以下是我初次建立 powerdns 服務的紀錄

環境
#

  • OS: Debian 12
  • DB: postgresql-14
  • pdns-server version: 4.7
1
apt install pdns-server pdns-backend-pgsql -y

事前準備
#

  1. 安裝 postgresql
  2. 建立資料庫
1
2
sudo su - postgres
psql
1
2
3
4
CREATE DATABASE pdnsdb;
CREATE USER pdns WITH PASSWORD 'pdnsPassword';
GRANT CONNECT ON DATABASE pdnsdb TO pdns;
ALTER DATABASE pdnsdb OWNER TO pdns;

建置 table schema,可以在說明文件中找到: /usr/share/doc/pdns-backend-pgsql/schema.pgsql.sql

並執行下列指令

1
psql -h <host> -U <user> <database> -f /usr/share/pdns-backend-pgsql/schema/schema.pgsql.sql

以下是內容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
CREATE TABLE domains (
  id                    SERIAL PRIMARY KEY,
  name                  VARCHAR(255) NOT NULL,
  master                VARCHAR(128) DEFAULT NULL,
  last_check            INT DEFAULT NULL,
  type                  TEXT NOT NULL,
  notified_serial       BIGINT DEFAULT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  options               TEXT DEFAULT NULL,
  catalog               TEXT DEFAULT NULL,
  CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);

CREATE UNIQUE INDEX name_index ON domains(name);
CREATE INDEX catalog_idx ON domains(catalog);


CREATE TABLE records (
  id                    BIGSERIAL PRIMARY KEY,
  domain_id             INT DEFAULT NULL,
  name                  VARCHAR(255) DEFAULT NULL,
  type                  VARCHAR(10) DEFAULT NULL,
  content               VARCHAR(65535) DEFAULT NULL,
  ttl                   INT DEFAULT NULL,
  prio                  INT DEFAULT NULL,
  disabled              BOOL DEFAULT 'f',
  ordername             VARCHAR(255),
  auth                  BOOL DEFAULT 't',
  CONSTRAINT domain_exists
  FOREIGN KEY(domain_id) REFERENCES domains(id)
  ON DELETE CASCADE,
  CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);

CREATE INDEX rec_name_index ON records(name);
CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);


CREATE TABLE supermasters (
  ip                    INET NOT NULL,
  nameserver            VARCHAR(255) NOT NULL,
  account               VARCHAR(40) NOT NULL,
  PRIMARY KEY(ip, nameserver)
);


CREATE TABLE comments (
  id                    SERIAL PRIMARY KEY,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  comment               VARCHAR(65535) NOT NULL,
  CONSTRAINT domain_exists
  FOREIGN KEY(domain_id) REFERENCES domains(id)
  ON DELETE CASCADE,
  CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);

CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);


CREATE TABLE domainmetadata (
  id                    SERIAL PRIMARY KEY,
  domain_id             INT REFERENCES domains(id) ON DELETE CASCADE,
  kind                  VARCHAR(32),
  content               TEXT
);

CREATE INDEX domainidmetaindex ON domainmetadata(domain_id);


CREATE TABLE cryptokeys (
  id                    SERIAL PRIMARY KEY,
  domain_id             INT REFERENCES domains(id) ON DELETE CASCADE,
  flags                 INT NOT NULL,
  active                BOOL,
  published             BOOL DEFAULT TRUE,
  content               TEXT
);

CREATE INDEX domainidindex ON cryptokeys(domain_id);


CREATE TABLE tsigkeys (
  id                    SERIAL PRIMARY KEY,
  name                  VARCHAR(255),
  algorithm             VARCHAR(50),
  secret                VARCHAR(255),
  CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);

安裝事前作業
#

  • 停用 systemd-resolved
1
sudo systemctl disable --now systemd-resolved

設定穩定版本來源
#

設定參考官方說明: PowerDNS repositories

  • /etc/apt/sources.list.d/pdns-stable.list
1
2
3
4
5
# PowerDNS Authoritative Server - stable branch
deb [signed-by=/etc/apt/keyrings/auth-49-pub.asc arch=amd64] http://repo.powerdns.com/debian bookworm-auth-49 main

# PowerDNS Recursor - stable branch
deb [signed-by=/etc/apt/keyrings/rec-51-pub.asc arch=amd64] http://repo.powerdns.com/debian bookworm-rec-51 main
  • /etc/apt/preferences.d/auth-49
1
2
3
Package: auth*
Pin: origin repo.powerdns.com
Pin-Priority: 600
  • /etc/apt/preferences.d/rec-51
1
2
3
Package: rec*
Pin: origin repo.powerdns.com
Pin-Priority: 600

安裝 PowerDNS
#

1
2
3
4
5
6
sudo install -d /etc/apt/keyrings; curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo tee /etc/apt/keyrings/auth-49-pub.asc
sudo install -d /etc/apt/keyrings; curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo tee /etc/apt/keyrings/rec-51-pub.asc
apt install -y pdns-server pdns-backend-pgsql pdns-recursor
cp /usr/share/doc/pdns-backend-pgsql/examples/gpgsql.conf /etc/powerdns/pdns.d/gpgsql.conf
chmod 0640 /etc/powerdns/pdns.d/gpgsql.conf
chgrp pdns /etc/powerdns/pdns.d/gpgsql.conf
  • 設定文件: /etc/powerdns/recursor.conf
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
#################################
# api-key	Static pre-shared authentication key for access to the REST API
#
# api-key=
api-key=<api-key>

#################################
# webserver     Start a webserver (for REST API)
#
# webserver=no
webserver=yes

#################################
# webserver-port        Port of webserver to listen on
#
# webserver-port=8082
webserver-port=8082

#################################
# webserver-address     IP Address of webserver to listen on
#
# webserver-address=127.0.0.1
webserver-address=0.0.0.0

#################################
# webserver-allow-from  Webserver access is only allowed from these subnets
#
# webserver-allow-from=127.0.0.1,::1
webserver-allow-from=0.0.0.0/0

#################################
# allow-from	If set, only allow these comma separated netmasks to recurse
#
# allow-from=127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10
#設定允許遞迥查詢內部網段
allow-from=127.0.0.1, 192.168.0.0/24  

#################################
# forward-zones	Zones for which we forward queries, comma separated domain=ip pairs
#
# forward-zones=
#轉送查詢的網域與伺服器,格式是 網域=伺服器ip,多個網域以逗點分隔
forward-zones=.=127.0.0.1:54  

#################################
# forward-zones-recurse Zones for which we forward queries with recursion bit, comma separated domain=ip pairs
#
# forward-zones-recurse=
#內部查詢不到會查到外部查詢
forward-zones-recurse=.=8.8.8.8, .=168.95.1.1 

#################################
# local-address	IP addresses to listen on, separated by spaces or commas. Also accepts ports.
#
# local-address=127.0.0.1
local-address=0.0.0.0

#################################
# local-port	port to listen on
#
# local-port=53
local-port=53

#################################
# logging-facility      Facility to log messages as. 0 corresponds to local0
#
# logging-facility=
logging-facility=0

#################################
# max-negative-ttl      maximum number of seconds to keep a negative cached entry in memory
#
# max-negative-ttl=3600
max-negative-ttl=3600

#################################
# setgid        If set, change group id to this gid for more security
#
setgid=pdns

#################################
# setuid        If set, change user id to this uid for more security
#
setuid=pdns

#################################
# config-dir	Location of configuration directory (recursor.conf)
#
config-dir=/etc/powerdns

#################################
# hint-file	If set, load root hints from this file
#
# hint-file=
hint-file=/usr/share/dns/root.hints

#################################
# include-dir	Include *.conf files from this directory
#
# include-dir=
include-dir=/etc/powerdns/recursor.d

#################################
# lua-config-file	More powerful configuration options
#
lua-config-file=/etc/powerdns/recursor.lua

#################################
# quiet	Suppress logging of questions and answers
#
quiet=yes
  • 設定文件: /etc/powerdns/pdns.conf
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
# Autogenerated configuration file template

#################################
# ignore-unknown-settings       Configuration settings to ignore if they are unknown
#
# ignore-unknown-settings=

#################################
# 8bit-dns      Allow 8bit dns queries
#
# 8bit-dns=no

#################################
# allow-axfr-ips        Allow zonetransfers only to these subnets
#
# allow-axfr-ips=127.0.0.0/8,::1

#################################
# allow-dnsupdate-from  A global setting to allow DNS updates from these IP ranges.
#
# allow-dnsupdate-from=127.0.0.0/8,::1

#################################
# allow-notify-from     Allow AXFR NOTIFY from these IP ranges. If empty, drop all incoming notifies.
#
# allow-notify-from=0.0.0.0/0,::/0

#################################
# allow-unsigned-autoprimary    Allow autoprimaries to create zones without TSIG signed NOTIFY
#
# allow-unsigned-autoprimary=yes

#################################
# allow-unsigned-notify Allow unsigned notifications for TSIG secured zones
#
# allow-unsigned-notify=yes

#################################
# allow-unsigned-supermaster    Allow supermasters to create zones without TSIG signed NOTIFY
#
# allow-unsigned-supermaster=yes

#################################
# also-notify   When notifying a zone, also notify these nameservers
#
# also-notify=

#################################
# any-to-tcp    Answer ANY queries with tc=1, shunting to TCP
#
# any-to-tcp=yes

#################################
# api   Enable/disable the REST API (including HTTP listener)
#
api=yes

#################################
# api-key       Static pre-shared authentication key for access to the REST API
#
api-key=<api-key>

#################################
# autosecondary Act as an autosecondary (formerly superslave)
#
# autosecondary=no

#################################
# axfr-fetch-timeout    Maximum time in seconds for inbound AXFR to start or be idle after starting
#
# axfr-fetch-timeout=10

#################################
# axfr-lower-serial     Also AXFR a zone from a master with a lower serial
#
# axfr-lower-serial=no

#################################
# cache-ttl     Seconds to store packets in the PacketCache
#
# cache-ttl=20

#################################
# carbon-instance       If set overwrites the instance name default
#
# carbon-instance=auth

#################################
# carbon-interval       Number of seconds between carbon (graphite) updates
#
# carbon-interval=30

#################################
# carbon-namespace      If set overwrites the first part of the carbon string
#
# carbon-namespace=pdns

#################################
# carbon-ourname        If set, overrides our reported hostname for carbon stats
#
# carbon-ourname=

#################################
# carbon-server If set, send metrics in carbon (graphite) format to this server IP address
#
# carbon-server=

#################################
# chroot        If set, chroot to this directory for more security
#
# chroot=

#################################
# config-dir    Location of configuration directory (pdns.conf)
#
# config-dir=/etc/powerdns

#################################
# config-name   Name of this virtual configuration - will rename the binary image
#
# config-name=

#################################
# consistent-backends   Assume individual zones are not divided over backends. Send only ANY lookup operations to the backend to reduce the number of lookups
#
# consistent-backends=yes

#################################
# control-console       Debugging switch - don't use
#
# control-console=no

#################################
# daemon        Operate as a daemon

daemon=yes

#################################
# default-api-rectify   Default API-RECTIFY value for zones
#
# default-api-rectify=yes

#################################
# default-ksk-algorithm Default KSK algorithm
#
# default-ksk-algorithm=ecdsa256

#################################
# default-ksk-size      Default KSK size (0 means default)
#
# default-ksk-size=0

#################################
# default-publish-cdnskey       Default value for PUBLISH-CDNSKEY
#
# default-publish-cdnskey=

#################################
# default-publish-cds   Default value for PUBLISH-CDS
#
# default-publish-cds=

#################################
# default-soa-content   Default SOA content
#
# default-soa-content=a.misconfigured.dns.server.invalid hostmaster.@ 0 10800 3600 604800 3600

#################################
# default-soa-edit      Default SOA-EDIT value
#
# default-soa-edit=

#################################
# default-soa-edit-signed       Default SOA-EDIT value for signed zones
#
# default-soa-edit-signed=

#################################
# default-ttl   Seconds a result is valid if not set otherwise
#
# default-ttl=3600

#################################
# default-zsk-algorithm Default ZSK algorithm
#
# default-zsk-algorithm=

#################################
# default-zsk-size      Default ZSK size (0 means default)
#
# default-zsk-size=0

#################################
# direct-dnskey Fetch DNSKEY, CDS and CDNSKEY RRs from backend during DNSKEY or CDS/CDNSKEY synthesis
#
# direct-dnskey=no

#################################
# disable-axfr  Disable zonetransfers but do allow TCP queries
#
# disable-axfr=no

#################################
# disable-axfr-rectify  Disable the rectify step during an outgoing AXFR. Only required for regression testing.
#
# disable-axfr-rectify=no

#################################
# disable-syslog        Disable logging to syslog, useful when running inside a supervisor that logs stdout
#
# disable-syslog=no

#################################
# distributor-threads   Default number of Distributor (backend) threads to start
#
# distributor-threads=3

#################################
# dname-processing      If we should support DNAME records
#
# dname-processing=no

#################################
# dnssec-key-cache-ttl  Seconds to cache DNSSEC keys from the database
#
# dnssec-key-cache-ttl=30

#################################
# dnsupdate     Enable/Disable DNS update (RFC2136) support. Default is no.
#
# dnsupdate=no

#################################
# domain-metadata-cache-ttl     Seconds to cache zone metadata from the database
#
# domain-metadata-cache-ttl=

#################################
# edns-cookie-secret    When set, set a server cookie when responding to a query with a Client cookie (in hex)
#
# edns-cookie-secret=

#################################
# edns-subnet-processing        If we should act on EDNS Subnet options
#
# edns-subnet-processing=no

#################################
# enable-lua-records    Process LUA records for all zones (metadata overrides this)
#
# enable-lua-records=no

#################################
# entropy-source        If set, read entropy from this file
#
# entropy-source=/dev/urandom

#################################
# expand-alias  Expand ALIAS records
#
# expand-alias=no

#################################
# forward-dnsupdate     A global setting to allow DNS update packages that are for a Slave zone, to be forwarded to the master.
#
# forward-dnsupdate=yes

#################################
# forward-notify        IP addresses to forward received notifications to regardless of master or slave settings
#
# forward-notify=

#################################
# guardian      Run within a guardian process
#
# guardian=no

#################################
# include-dir   Include *.conf files from this directory
#
# include-dir=
include-dir=/etc/powerdns/pdns.d

#################################
# launch        Which backends to launch and order to query them in
#
# launch=
launch=

#################################
# load-modules  Load this module - supply absolute or relative path
#
# load-modules=

#################################
# local-address Local IP addresses to which we bind
#
local-address=0.0.0.0, ::

#################################
# local-address-nonexist-fail   Fail to start if one or more of the local-address's do not exist on this server
#
# local-address-nonexist-fail=yes

#################################
# local-port    The port on which we listen
#
local-port=54

#################################
# log-dns-details       If PDNS should log DNS non-erroneous details
#
log-dns-details=yes

#################################
# log-dns-queries       If PDNS should log all incoming DNS queries
#
log-dns-queries=yes

#################################
# log-timestamp Print timestamps in log lines
log-timestamp=yes

#################################
# logging-facility      Log under a specific facility
#
logging-facility=0

#################################
# loglevel      Amount of logging. Higher is more. Do not set below 3
#
loglevel=4

#################################
# lua-axfr-script       Script to be used to edit incoming AXFRs
#
# lua-axfr-script=

#################################
# lua-dnsupdate-policy-script   Lua script with DNS update policy handler
#
# lua-dnsupdate-policy-script=

#################################
# lua-health-checks-expire-delay        Stops doing health checks after the record hasn't been used for that delay (in seconds)
#
# lua-health-checks-expire-delay=3600

#################################
# lua-health-checks-interval    LUA records health checks monitoring interval in seconds
#
# lua-health-checks-interval=5

#################################
# lua-prequery-script   Lua script with prequery handler (DO NOT USE)
#
# lua-prequery-script=

#################################
# lua-records-exec-limit        LUA records scripts execution limit (instructions count). Values <= 0 mean no limit
#
# lua-records-exec-limit=1000

#################################
# master        Act as a primary
#
# master=no

#################################
# max-cache-entries     Maximum number of entries in the query cache
#
# max-cache-entries=1000000

#################################
# max-ent-entries       Maximum number of empty non-terminals in a zone
#
# max-ent-entries=100000

#################################
# max-generate-steps    Maximum number of $GENERATE steps when loading a zone from a file
#
# max-generate-steps=0

#################################
# max-include-depth     Maximum number of nested $INCLUDE directives while processing a zone file
#
# max-include-depth=20

#################################
# max-nsec3-iterations  Limit the number of NSEC3 hash iterations
#
# max-nsec3-iterations=100

#################################
# max-packet-cache-entries      Maximum number of entries in the packet cache
#
# max-packet-cache-entries=1000000

#################################
# max-queue-length      Maximum queuelength before considering situation lost
#
# max-queue-length=5000

#################################
# max-signature-cache-entries   Maximum number of signatures cache entries
#
# max-signature-cache-entries=

#################################
# max-tcp-connection-duration   Maximum time in seconds that a TCP DNS connection is allowed to stay open.
#
# max-tcp-connection-duration=0

#################################
# max-tcp-connections   Maximum number of TCP connections
#
# max-tcp-connections=20

#################################
# max-tcp-connections-per-client        Maximum number of simultaneous TCP connections per client
#
# max-tcp-connections-per-client=0

#################################
# max-tcp-transactions-per-conn Maximum number of subsequent queries per TCP connection
#
# max-tcp-transactions-per-conn=0

#################################
# module-dir    Default directory for modules
#


#################################
# negquery-cache-ttl    Seconds to store negative query results in the QueryCache
#
# negquery-cache-ttl=60

#################################
# no-shuffle    Set this to prevent random shuffling of answers - for regression testing
#
# no-shuffle=off

#################################
# non-local-bind        Enable binding to non-local addresses by using FREEBIND / BINDANY socket options
#
# non-local-bind=no

#################################
# only-notify   Only send AXFR NOTIFY to these IP addresses or netmasks
#
# only-notify=0.0.0.0/0,::/0

#################################
# outgoing-axfr-expand-alias    Expand ALIAS records during outgoing AXFR
#
# outgoing-axfr-expand-alias=no

#################################
# overload-queue-length Maximum queuelength moving to packetcache only
#
# overload-queue-length=0

#################################
# prevent-self-notification     Don't send notifications to what we think is ourself
#
# prevent-self-notification=yes

#################################
# primary       Act as a primary
#
# primary=no

#################################
# proxy-protocol-from   A Proxy Protocol header is only allowed from these subnets, and is mandatory then too.
#
# proxy-protocol-from=

#################################
# proxy-protocol-maximum-size   The maximum size of a proxy protocol payload, including the TLV values
#
# proxy-protocol-maximum-size=512

#################################
# query-cache-ttl       Seconds to store query results in the QueryCache
#
# query-cache-ttl=20

#################################
# query-local-address   Source IP addresses for sending queries
#
# query-local-address=0.0.0.0 ::

#################################
# query-logging Hint backends that queries should be logged
#
query-logging=yes

#################################
# queue-limit   Maximum number of milliseconds to queue a query
#
# queue-limit=1500

#################################
# receiver-threads      Default number of receiver threads to start
#
# receiver-threads=1

#################################
# resolver      Use this resolver for ALIAS and the internal stub resolver
#
# resolver=no

#################################
# retrieval-threads     Number of AXFR-retrieval threads for slave operation
#
# retrieval-threads=2

#################################
# reuseport     Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket
#
# reuseport=no

#################################
# rng   Specify the random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.
#
# rng=auto

#################################
# secondary     Act as a secondary
#
# secondary=no

#################################
# secondary-check-signature-freshness   Check signatures in SOA freshness check. Sets DO flag on SOA queries. Outside some very problematic scenarios, say yes here.
#
# secondary-check-signature-freshness=yes

#################################
# secondary-do-renotify If this secondary should send out notifications after receiving zone transfers from a primary
#
# secondary-do-renotify=no

#################################
# security-poll-suffix  Zone name from which to query security update notifications
#
# security-poll-suffix=secpoll.powerdns.com.
security-poll-suffix=

#################################
# send-signed-notify    Send TSIG secured NOTIFY if TSIG key is configured for a zone
#
# send-signed-notify=yes

#################################
# server-id     Returned when queried for 'id.server' TXT or NSID, defaults to hostname - disabled or custom
#
# server-id=

#################################
# setgid        If set, change group id to this gid for more security
#
setgid=pdns

#################################
# setuid        If set, change user id to this uid for more security
#
setuid=pdns

#################################
# signing-threads       Default number of signer threads to start
#
# signing-threads=3

#################################
# slave Act as a secondary
#
# slave=no

#################################
# slave-cycle-interval  Schedule slave freshness checks once every .. seconds
#
# slave-cycle-interval=60

#################################
# slave-renotify        If we should send out notifications for secondaried updates
#
# slave-renotify=no

#################################
# socket-dir    Where the controlsocket will live, /var/run/pdns when unset and not chrooted. Set to the RUNTIME_DIRECTORY environment variable when that variable has a value (e.g. under systemd).
#
# socket-dir=

#################################
# superslave    Act as a autosecondary
#
# superslave=no

#################################
# svc-autohints Transparently fill ipv6hint=auto ipv4hint=auto SVC params with AAAA/A records for the target name of the record (if within the same zone)
#
# svc-autohints=no

#################################
# tcp-control-address   If set, PowerDNS can be controlled over TCP on this address
#
# tcp-control-address=

#################################
# tcp-control-port      If set, PowerDNS can be controlled over TCP on this address
#
# tcp-control-port=53000

#################################
# tcp-control-range     If set, remote control of PowerDNS is possible over these networks only
#
# tcp-control-range=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10

#################################
# tcp-control-secret    If set, PowerDNS can be controlled over TCP after passing this secret
#
# tcp-control-secret=

#################################
# tcp-fast-open Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size
#
# tcp-fast-open=0

#################################
# tcp-idle-timeout      Maximum time in seconds that a TCP DNS connection is allowed to stay open while being idle
#
# tcp-idle-timeout=5

#################################
# traceback-handler     Enable the traceback handler (Linux only)
#
# traceback-handler=yes

#################################
# trusted-notification-proxy    IP address of incoming notification proxy
#
# trusted-notification-proxy=

#################################
# udp-truncation-threshold      Maximum UDP response size before we truncate
#
# udp-truncation-threshold=1232

#################################
# upgrade-unknown-types Transparently upgrade known TYPExxx records. Recommended to keep off, except for PowerDNS upgrades until data sources are cleaned up
#
# upgrade-unknown-types=no

#################################
# version-string        PowerDNS version in packets - full, anonymous, powerdns or custom
#
# version-string=full

#################################
# webserver     Start a webserver for monitoring (api=yes also enables the HTTP listener)
#
webserver=yes

#################################
# webserver-address     IP Address of webserver/API to listen on
#
webserver-address=0.0.0.0

#################################
# webserver-allow-from  Webserver/API access is only allowed from these subnets
#
webserver-allow-from=0.0.0.0/0

#################################
# webserver-hash-plaintext-credentials  Whether to hash passwords and api keys supplied in plaintext, to prevent keeping the plaintext version in memory at runtime
#
# webserver-hash-plaintext-credentials=no

#################################
# webserver-loglevel    Amount of logging in the webserver (none, normal, detailed)
#
# webserver-loglevel=normal

#################################
# webserver-max-bodysize        Webserver/API maximum request/response body size in megabytes
#
# webserver-max-bodysize=2

#################################
# webserver-password    Password required for accessing the webserver
#
# webserver-password=

#################################
# webserver-port        Port of webserver/API to listen on
#
webserver-port=8081

#################################
# webserver-print-arguments     If the webserver should print arguments
#
# webserver-print-arguments=no

#################################
# write-pid     Write a PID file
#
# write-pid=yes

#################################
# xfr-cycle-interval    Schedule primary/secondary SOA freshness checks once every .. seconds
#
# xfr-cycle-interval=60

#################################
# xfr-max-received-mbytes       Maximum number of megabytes received from an incoming XFR
#
# xfr-max-received-mbytes=100

#################################
# zone-cache-refresh-interval   Seconds to cache list of known zones
#
# zone-cache-refresh-interval=300

#################################
# zone-metadata-cache-ttl       Seconds to cache zone metadata from the database
#
# zone-metadata-cache-ttl=60
  • 設定文件: /etc/powerdns/pdns.d/gpgsql.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# See https://doc.powerdns.com/authoritative/backends/generic-postgresql.html
launch+=gpgsql

#################################
# gpgsql-dbname Backend database name to connect to
#
# gpgsql-dbname=
gpgsql-dbname=pdnsdb

#################################
# gpgsql-dnssec Enable DNSSEC processing
#
# gpgsql-dnssec=no
gpgsql-dnssec=yes

#################################
# gpgsql-extra-connection-parameters    Extra parameters to add to connection string
#
# gpgsql-extra-connection-parameters=

#################################
# gpgsql-host   Database backend host to connect to
#
# gpgsql-host=
gpgsql-host=127.0.0.1

#################################
# gpgsql-password       Database backend password to connect with
#
# gpgsql-password=
gpgsql-password=pdnsPassword

#################################
# gpgsql-port   Database backend port to connect to
#
# gpgsql-port=
gpgsql-port=5432

#################################
# gpgsql-prepared-statements    Use prepared statements instead of parameterized queries
#
# gpgsql-prepared-statements=yes

#################################
# gpgsql-user   Database backend user to connect as
#
# gpgsql-user=
gpgsql-user=pdns
1
systemctl enable pdns ; systemctl restart pdns

設定 log
#

編輯 system daemon

1
systemctl edit --full pdns

移除 --disable-syslog --log-timestamp=no

  • /etc/rsyslog.d/pdns.conf
1
2
3
local0.info                       -/var/log/pdns/pdns.info
local0.warn                       -/var/log/pdns/pdns.warn
local0.err                        /var/log/pdns/pdns.err
1
2
3
mkdir -p /var/log/pdns
chown pdns:pdns /var/log/pdns
systemctl restart pdns rsyslog

安裝 PowerDNS-Admin
#

設定資料庫
#

1
2
3
4
CREATE DATABASE pdnsadmindb;
CREATE USER pdnsadmin WITH PASSWORD 'pdnsPassword';
GRANT CONNECT ON DATABASE pdnsadmindb TO pdnsadmin;
ALTER DATABASE pdnsadmindb OWNER TO pdnsadmin;

執行安裝
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
sudo -i
# 預先安裝必要套件
apt install -y python3.11-venv python3-psycopg2 libmariadb-dev libsasl2-dev libldap2-dev libssl-dev libxml2-dev libxslt1-dev libxmlsec1-dev libffi-dev pkg-config apt-transport-https virtualenv build-essential python3-venv libpq-dev python3-dev

# 安裝NodeJS
sudo apt-get install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
export NODE_MAJOR=20
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
apt install -y nodejs

# 安裝 yarn
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update
sudo apt install -y yarn

# 安裝 PowerDNS-Admin
wget -O /tmp/PowerDNS-Admin.tar.gz https://github.com/PowerDNS-Admin/PowerDNS-Admin/archive/refs/tags/v0.4.2.tar.gz
mkdir -p /opt/web/
tar -zxf /tmp/PowerDNS-Admin.tar.gz -C /opt/web/
ln -s /opt/web/PowerDNS-Admin-0.4.2 /opt/web/powerdns-admin
cd /opt/web/powerdns-admin
python3 -mvenv ./venv
source ./venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
1
cp /opt/web/powerdns-admin/configs/development.py /opt/web/powerdns-admin/configs/production.py
  • 設定文件: /opt/web/powerdns-admin/configs/production.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
import os
import urllib.parse
basedir = os.path.abspath(os.path.dirname(__file__))

### BASIC APP CONFIG
SALT = '$2b$12$yLUMTIfl21FKJQpTkRQXCu'
SECRET_KEY = 'e951e5a1f4b94151b360f47edf596dd2'
BIND_ADDRESS = '0.0.0.0'
PORT = 9191
SERVER_EXTERNAL_SSL = os.getenv('SERVER_EXTERNAL_SSL', None)

### DATABASE CONFIG
SQLA_DB_USER = 'pdnsadmin'
SQLA_DB_PASSWORD = 'pdnsPassword'
SQLA_DB_HOST = '127.0.0.1'
SQLA_DB_NAME = 'pdnsadmindb'
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLA_DB_PORT = 5432

#CAPTCHA Config
CAPTCHA_ENABLE = True
CAPTCHA_LENGTH = 6
CAPTCHA_WIDTH = 160
CAPTCHA_HEIGHT = 60
CAPTCHA_SESSION_KEY = 'captcha_image'

#Server side sessions tracking
#Set to TRUE for CAPTCHA, or enable another stateful session tracking system
SESSION_TYPE = 'sqlalchemy'

### DATABASE - MySQL
## Don't forget to uncomment the import in the top
#SQLALCHEMY_DATABASE_URI = 'mysql://{}:{}@{}/{}'.format(
#    urllib.parse.quote_plus(SQLA_DB_USER),
#    urllib.parse.quote_plus(SQLA_DB_PASSWORD),
#    SQLA_DB_HOST,
#    SQLA_DB_NAME
#)

### DATABASE - PostgreSQL
## Don't forget to uncomment the import in the top
SQLALCHEMY_DATABASE_URI = 'postgresql://{}:{}@{}:{}/{}'.format(
   urllib.parse.quote_plus(SQLA_DB_USER),
   urllib.parse.quote_plus(SQLA_DB_PASSWORD),
   SQLA_DB_HOST,
   SQLA_DB_PORT,
   SQLA_DB_NAME
)

### DATABASE - SQLite
# SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'pdns.db')

### SMTP config
# MAIL_SERVER = 'localhost'
# MAIL_PORT = 25
# MAIL_DEBUG = False
# MAIL_USE_TLS = False
# MAIL_USE_SSL = False
# MAIL_USERNAME = None
# MAIL_PASSWORD = None
# MAIL_DEFAULT_SENDER = ('PowerDNS-Admin', '[email protected]')

# SAML Authnetication
SAML_ENABLED = False
# SAML_DEBUG = True
# SAML_PATH = os.path.join(os.path.dirname(__file__), 'saml')
# ##Example for ADFS Metadata-URL
# SAML_METADATA_URL = 'https://<hostname>/FederationMetadata/2007-06/FederationMetadata.xml'
# #Cache Lifetime in Seconds
# SAML_METADATA_CACHE_LIFETIME = 1

# # SAML SSO binding format to use
# ## Default: library default (urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect)
# #SAML_IDP_SSO_BINDING = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'

# ## EntityID of the IdP to use. Only needed if more than one IdP is
# ##   in the SAML_METADATA_URL
# ### Default: First (only) IdP in the SAML_METADATA_URL
# ### Example: https://idp.example.edu/idp
# #SAML_IDP_ENTITY_ID = 'https://idp.example.edu/idp'
# ## NameID format to request
# ### Default: The SAML NameID Format in the metadata if present,
# ###   otherwise urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
# ### Example: urn:oid:0.9.2342.19200300.100.1.1
# #SAML_NAMEID_FORMAT = 'urn:oid:0.9.2342.19200300.100.1.1'

# Following parameter defines RequestedAttributes section in SAML metadata
# since certain iDPs require explicit attribute request. If not provided section
# will not be available in metadata.
#
# Possible attributes:
# name (mandatory), nameFormat, isRequired, friendlyName
#
# NOTE: This parameter requires to be entered in valid JSON format as displayed below
# and multiple attributes can given
#
# Following example:
#
# SAML_SP_REQUESTED_ATTRIBUTES = '[ \
# {"name": "urn:oid:0.9.2342.19200300.100.1.3", "nameFormat": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", "isRequired": true, "friendlyName": "email"}, \
# {"name": "mail", "isRequired": false, "friendlyName": "test-field"} \
# ]'
#
# produces following metadata section:
# <md:AttributeConsumingService index="1">
# <md:RequestedAttribute Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="email" isRequired="true"/>
# <md:RequestedAttribute Name="mail" FriendlyName="test-field"/>
# </md:AttributeConsumingService>


# ## Attribute to use for Email address
# ### Default: email
# ### Example: urn:oid:0.9.2342.19200300.100.1.3
# #SAML_ATTRIBUTE_EMAIL = 'urn:oid:0.9.2342.19200300.100.1.3'

# ## Attribute to use for Given name
# ### Default: givenname
# ### Example: urn:oid:2.5.4.42
# #SAML_ATTRIBUTE_GIVENNAME = 'urn:oid:2.5.4.42'

# ## Attribute to use for Surname
# ### Default: surname
# ### Example: urn:oid:2.5.4.4
# #SAML_ATTRIBUTE_SURNAME = 'urn:oid:2.5.4.4'

# ## Attribute to use for username
# ### Default: Use NameID instead
# ### Example: urn:oid:0.9.2342.19200300.100.1.1
# #SAML_ATTRIBUTE_USERNAME = 'urn:oid:0.9.2342.19200300.100.1.1'

# ## Attribute to get admin status from
# ### Default: Don't control admin with SAML attribute
# ### Example: https://example.edu/pdns-admin
# ### If set, look for the value 'true' to set a user as an administrator
# ### If not included in assertion, or set to something other than 'true',
# ###  the user is set as a non-administrator user.
# #SAML_ATTRIBUTE_ADMIN = 'https://example.edu/pdns-admin'

## Attribute to get admin status for groups with the IdP
# ### Default: Don't set administrator group with SAML attributes
#SAML_GROUP_ADMIN_NAME = 'GroupName'

## Attribute to get operator status for groups with the IdP
# ### Default: Don't set operator group with SAML attributes
#SAML_GROUP_OPERATOR_NAME = 'GroupName'

# ## Attribute to get account names from
# ### Default: Don't control accounts with SAML attribute
# ### If set, the user will be added and removed from accounts to match
# ###  what's in the login assertion. Accounts that don't exist will
# ###  be created and the user added to them.
# SAML_ATTRIBUTE_ACCOUNT = 'https://example.edu/pdns-account'

# ## Attribute name that aggregates group names
# ### Default: Don't collect IdP groups from SAML group attributes
# ### In Okta, you can assign administrators by group using "Group Attribute Statements."
# ### In this case, the SAML_ATTRIBUTE_GROUP will be the attribute name for a collection of
# ###  groups passed in the SAML assertion.  From there, you can specify a SAML_GROUP_ADMIN_NAME.
# ### If the user is a member of this group, and that group name is included in the collection,
# ###   the user will be set as an administrator.
# #SAML_ATTRIBUTE_GROUP = 'https://example.edu/pdns-groups'
# #SAML_GROUP_ADMIN_NAME = 'PowerDNSAdmin-Administrators'

# SAML_SP_ENTITY_ID = 'http://<SAML SP Entity ID>'
# SAML_SP_CONTACT_NAME = '<contact name>'
# SAML_SP_CONTACT_MAIL = '<contact mail>'

# Configures the path to certificate file and it's respective private key file
# This pair is used for signing metadata, encrypting tokens and all other signing/encryption
# tasks during communication between iDP and SP
# NOTE: if this two parameters aren't explicitly provided, self-signed certificate-key pair
# will be generated in "PowerDNS-Admin" root directory
# ###########################################################################################
# CAUTION: For production use, usage of self-signed certificates it's highly discouraged.
# Use certificates from trusted CA instead
# ###########################################################################################
# SAML_CERT = '/etc/pki/powerdns-admin/cert.crt'
# SAML_KEY = '/etc/pki/powerdns-admin/key.pem'

# Configures if SAML tokens should be encrypted.
# SAML_SIGN_REQUEST = False
# #Use SAML standard logout mechanism retreived from idp metadata
# #If configured false don't care about SAML session on logout.
# #Logout from PowerDNS-Admin only and keep SAML session authenticated.
# SAML_LOGOUT = False
# #Configure to redirect to a different url then PowerDNS-Admin login after SAML logout
# #for example redirect to google.com after successful saml logout
# #SAML_LOGOUT_URL = 'https://google.com'

# #SAML_ASSERTION_ENCRYPTED = True

# Some IdPs, like Okta, do not return Attribute Statements by default
# Set the following to False if you are using Okta and not manually configuring Attribute Statements
# #SAML_WANT_ATTRIBUTE_STATEMENT = True

# Remote authentication settings

# Whether to enable remote user authentication or not
# Defaults to False
# REMOTE_USER_ENABLED=True

# If set, users will be redirected to this location on logout
# Ignore or set to None to avoid redirecting altogether
# Warning: if REMOTE_USER environment variable is still set after logging out and not cleared by
# some external module, not defining a custom logout URL might trigger a loop
# that will just log the user back in right after logging out
# REMOTE_USER_LOGOUT_URL=https://my.sso.com/cas/logout

# An optional list of remote authentication tied cookies to be removed upon logout
# REMOTE_USER_COOKIES=['MOD_AUTH_CAS', 'MOD_AUTH_CAS_S']
1
2
3
export FLASK_CONF=../configs/production.py
export FLASK_APP=powerdnsadmin/__init__.py
flask db upgrade

操作結果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
(venv) root@pl-dns-01:/opt/web/powerdns-admin# export FLASK_CONF=../configs/production.py
(venv) root@pl-dns-01:/opt/web/powerdns-admin# export FLASK_APP=powerdnsadmin/__init__.py
(venv) root@pl-dns-01:/opt/web/powerdns-admin# flask db upgrade
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 787bdba9e147, Init DB
INFO  [alembic.runtime.migration] Running upgrade 787bdba9e147 -> 59729e468045, Add view column to setting table
INFO  [alembic.runtime.migration] Running upgrade 59729e468045 -> 1274ed462010, Change setting.value data type
INFO  [alembic.runtime.migration] Running upgrade 1274ed462010 -> 4a666113c7bb, Adding Operator Role
INFO  [alembic.runtime.migration] Running upgrade 4a666113c7bb -> 31a4ed468b18, Remove all setting in the DB
INFO  [alembic.runtime.migration] Running upgrade 31a4ed468b18 -> 654298797277, Upgrade DB Schema
INFO  [alembic.runtime.migration] Running upgrade 654298797277 -> 0fb6d23a4863, Remove user avatar
INFO  [alembic.runtime.migration] Running upgrade 0fb6d23a4863 -> 856bb94b7040, Add comment column in domain template record table
INFO  [alembic.runtime.migration] Running upgrade 856bb94b7040 -> b0fea72a3f20, Update domain serial columns type
INFO  [alembic.runtime.migration] Running upgrade b0fea72a3f20 -> 3f76448bb6de, Add user.confirmed column
INFO  [alembic.runtime.migration] Running upgrade 3f76448bb6de -> 0d3d93f1c2e0, Add domain_id to history table
INFO  [alembic.runtime.migration] Running upgrade 0d3d93f1c2e0 -> 0967658d9c0d, add apikey account mapping table
INFO  [alembic.runtime.migration] Running upgrade 0967658d9c0d -> fbc7cf864b24, update history detail quotes
INFO  [alembic.runtime.migration] Running upgrade fbc7cf864b24 -> 6ea7dc05f496, Fix typo in history detail
INFO  [alembic.runtime.migration] Running upgrade 6ea7dc05f496 -> f41520e41cee, update domain type length
INFO  [alembic.runtime.migration] Running upgrade f41520e41cee -> b24bf17725d2, Add unique index to settings table keys

產生資料檔
#

1
2
yarn install --pure-lockfile
flask assets build

操作結果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(venv) root@pl-dns-01:/opt/web/powerdns-admin# yarn install --pure-lockfile
yarn install v1.22.22
[1/4] Resolving packages...
warning Resolution field "@fortawesome/[email protected]" is incompatible with requested version "@fortawesome/fontawesome-free@^5.15.4"
[2/4] Fetching packages...
info There appears to be trouble with your network connection. Retrying...
[3/4] Linking dependencies...
warning " > [email protected]" has unmet peer dependency "[email protected] - 3".
warning " > [email protected]" has unmet peer dependency "popper.js@^1.16.1".
warning "admin-lte > [email protected]" has incorrect peer dependency "bootstrap@^3.1.1".
warning " > [email protected]" has unmet peer dependency "jquery@^1.7 || ^2.0 || ^3.1".
warning "admin-lte > [email protected]" has unmet peer dependency "moment-timezone@^0.5.31".
warning "admin-lte > [email protected]" has unmet peer dependency "[email protected]".
warning "admin-lte > bootstrap-colorpicker > [email protected]" has unmet peer dependency "@popperjs/core@^2.11.6".
[4/4] Building fresh packages...
Done in 29.55s.
(venv) root@pl-dns-01:/opt/web/powerdns-admin# flask assets build
Building bundle: generated/login.js
[2024-12-22 22:51:03,754] [script.py:167] INFO - Building bundle: generated/login.js
Building bundle: generated/validation.js
[2024-12-22 22:51:03,763] [script.py:167] INFO - Building bundle: generated/validation.js
Building bundle: generated/login.css
[2024-12-22 22:51:03,765] [script.py:167] INFO - Building bundle: generated/login.css
Building bundle: generated/main.js
[2024-12-22 22:51:03,812] [script.py:167] INFO - Building bundle: generated/main.js
Building bundle: generated/main.css
[2024-12-22 22:51:03,857] [script.py:167] INFO - Building bundle: generated/main.css
(venv) root@pl-dns-01:/opt/web/powerdns-admin# 

記下當前版本 PowerDNS 當前版本,等等設定會使用到

1
sudo pdns_control version

試營運

1
./run.py

URL: http://192.168.56.100:9191/login

  • 預設使沒有登入帳號的,需要先註冊一個帳號

離開 Python 虛擬環境

1
deactivate

建立 system-daemon
#

  • /etc/systemd/system/powerdns-admin.service
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Unit]
Description=PowerDNS-Admin
Requires=powerdns-admin.socket
After=network.target

[Service]
Environment="FLASK_CONF=../configs/production.py"
PIDFile=/run/powerdns-admin/pid
User=pdns
Group=pdns
WorkingDirectory=/opt/web/powerdns-admin
ExecStart=/opt/web/powerdns-admin/venv/bin/gunicorn --pid /run/powerdns-admin/pid --bind unix:/run/powerdns-admin/socket 'powerdnsadmin:create_app()'
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
  • /etc/systemd/system/powerdns-admin.socket
1
2
3
4
5
6
7
8
[Unit]
Description=PowerDNS-Admin socket

[Socket]
ListenStream=/run/powerdns-admin/socket

[Install]
WantedBy=sockets.target
  • /etc/tmpfiles.d/powerdns-admin.conf
1
d /run/powerdns-admin 0755 pdns pdns -
1
2
3
4
sudo systemctl daemon-reload && sudo systemctl start powerdns-admin.socket && sudo systemctl enable powerdns-admin.socket
sudo chown -R pdns:pdns /run/powerdns-admin
sudo chown -R pdns:pdns /opt/web/PowerDNS-Admin-0.4.2
sudo systemctl restart powerdns-admin

安裝 nginx
#

1
apt install nginx
  • /etc/nginx/conf.d/http.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
server {
  listen *:80;
  server_name               192.168.56.100;

  index                     index.html index.htm index.php;
  root                      /opt/web/powerdns-admin;
  access_log                /var/log/nginx/powerdns-admin.local.access.log combined;
  error_log                 /var/log/nginx/powerdns-admin.local.error.log;

  client_max_body_size              10m;
  client_body_buffer_size           128k;
  proxy_redirect                    off;
  proxy_connect_timeout             90;
  proxy_send_timeout                90;
  proxy_read_timeout                90;
  proxy_buffers                     32 4k;
  proxy_buffer_size                 8k;
  proxy_set_header                  Host $host;
  proxy_set_header                  X-Real-IP $remote_addr;
  proxy_set_header                  X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_headers_hash_bucket_size    64;

  location ~ ^/static/  {
    include  /etc/nginx/mime.types;
    root /opt/web/powerdns-admin/powerdnsadmin;

    location ~*  \.(jpg|jpeg|png|gif)$ {
      expires 365d;
    }

    location ~* ^.+.(css|js)$ {
      expires 7d;
    }
  }

  location / {
    proxy_pass            http://unix:/run/powerdns-admin/socket;
    proxy_read_timeout    120;
    proxy_connect_timeout 120;
    proxy_redirect        off;
  }

}

測試
#

1
2
dig @172.30.1.101 pl-dns-01.home.pollochang.work A
nslookup pl-dns-01.home.pollochang.work 172.30.1.101

參考資料
#