banner
NEWS LETTER

前端开发环境调优

Scroll down

背景

有一个常见的开发场景:

  1. 本地同时启动多个项目;
  2. 需要以https的方式访问开发页面;
  3. 需要以域名访问开发页面,且通常是指定域名的子域。例如生产环境是 example.com,开发环境则是local.example.com;

问题1,2可以在本地跑一个nginx为运行在不同端口的项目做反向代理,同时能提供https环境。为方便地修改ng配置,再运行一个nginx-ui项目提供UI界面,现在要将这个nginx-ui设置为自启动。

对问题3,计划在本地跑一个dns服务器,以泛域名解析的方式将以指定域名通通解析到本地127.0.0.1,例如将所有xxx.loc.example.net 都指向127.0.0.1,每次有新的项目启动就不需要手动修改host文件,配合nginx根据server_name转发到对应端口。为了使nginx的配置更通用化,基于命名约定,利用nginx的正则匹配功能实现:仅根据域名就能判定需要把请求代理到哪个端口。

最后写一个自启动脚本将上述 nginx 和 dnsmasq 服务加入到mac的自启动项目。

下面是详细步骤:

关于dnsmasq

dnsmasq 用于为小型网络提供网络设施:包括DNS,DHCP,路由器广告,支持Linux android,MacOS
DNS子系统提供了一个本地dns服务器,会转发所有查询类型到上游递归DNS服务器,并缓存常用记录类型,比如A,AAAA,CNAME等

dnsmasq的安装和配置

在macos下通常可以使用brew安装和更新dnsmasq,dnsmasq会加入到brew services

1
2
brew install dnsmasq
brew services list


通过dnsmasq.conf配置文件(位于/usr/local/etc/dnsmasq.conf)来配置dnsmasq的各种功能(所有配置项详见附录)

按照上面讲的,我们需要dnsmasq做两件事:

  1. 将所有以loc.example.com 结尾的域名解析到127.0.0.1
  2. 设置上游dns,其他普通的dns查询通通交给上游dns解析

下面是用到的几个主要配置项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 完整的域名才向上游查询,否则返回本地的hosts文件
domain-needed

# 上游服务器配置,默认情况下是/etc/resolv.conf,这是系统自动生成的的dns文件,一般是从dhcp获得,因为我们需要把resolv.conf中的dns服务器换成本地127.0.0.1,这里改成其他文件,其中内容由脚本自动生成,取自原本应该在resolv.conf的内容
resolv-file=/var/run/dnsmasq.upstreams.conf

# 仅监听本地的dns查询请求,如有需要可改成在局域网监听
listen-address=127.0.0.1

# 额外的dnsmasq配置
conf-dir=/usr/local/etc/dnsmasq.d,.bak

# 指定域名发往指定dns,将所有aaa.com的查询请求转发到xxx.xx.xx.xx这个dns
server=/aaa.com/xxx.xx.xx.xx

# 指定域名解析到127.0.0.1
address=/loc.expmple.com/127.0.0.1

其中比较麻烦的一点是如何获取上游dns,写入到dnsmasq.upstreams.conf中,以保证普通的dns请求正常返回。还有一个问题是如果处于企业内网中,普通dns请求可能包括:公网网址和企业内部网址,他们可能需要通过不同的dns解析。
下面是一个可参考的脚本:【注:脚本并不完善,因为经检查本司没有专门给内部网址解析的dns,都是用一台公网dns解析(这可能有点奇怪),所以脚本内没有针对企业内网网址的处理】

fold
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
LOG_FILE="/var/log/auto_update_dns.log"

DNSMASQ_UPSTREAMS_FILE="/var/run/dnsmasq.upstreams.conf"

DNSMASQ_CONFIG_DIR="/usr/local/etc/dnsmasq.d"
ENTERPRISE_DNS_CONF="${DNSMASQ_CONFIG_DIR}/enterprise-dns.conf"
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | sudo tee -a "$LOG_FILE" > /dev/null
}

# 获取当前Wi-Fi服务的名称
get_wifi_service_name() {
networksetup -listallnetworkservices | grep -i "wi-fi" | head -n 1 | sed 's/^\* //g' | xargs
}

# 获取当前Wi-Fi网络的SSID
get_current_ssid() {
system_profiler SPAirPortDataType | awk '/Current Network/ {getline;$1=$1; gsub(":",""); print;exit}'
}

# 获取指定网络服务的当前DNS服务器
get_current_network_dns() {
local service_name="$1"
networksetup -getdnsservers "$service_name" | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
}

WIFI_SERVICE=$(get_wifi_service_name)
if [ -z "$WIFI_SERVICE" ]; then
log_message "Error: Wi-Fi service not found. Exiting."
exit 1
fi
log_message "detected wifi service '$WIFI_SERVICE'"
echo $WIFI_SERVICE

CURRENT_SSID=$(get_current_ssid)
log_message "Current SSID: '$CURRENT_SSID'"
echo $CURRENT_SSID

# 获取当前wifi的dns服务器,通过DHCP获取
# 查找当前wifi接口名
ACTIVE_WIFI_IFACE=$(networksetup -listallhardwareports | awk '/Hardware Port: Wi-Fi/{getline; print $NF}')
log_message "Active Wi-Fi Interface: '$ACTIVE_WIFI_IFACE'"

DHCP_DNS_SERVER=""
if [ -n "$ACTIVE_WIFI_IFACE" ]; then
# 使用 ipconfig getoption 获取 DHCP 分配的 DNS 服务器
# 这是获取原始DHCP DNS的可靠方法,因为它直接查询DHCP租约信息
# 确保只匹配IPv4地址
DHCP_DNS_SERVERS=$(ipconfig getoption "$ACTIVE_WIFI_IFACE" domain_name_server | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' | tr '\n' ' ')
echo "'$ACTIVE_WIFI_IFACE': $DHCP_DNS_SERVERS"
log_message "DHCP-assigned DNS servers for '$ACTIVE_WIFI_IFACE': $DHCP_DNS_SERVERS"
else
log_message "Warning: Could not determine active Wi-Fi interface. DHCP DNS not queried."
fi

# Fallback: 如果没有获取到DHCP DNS,则使用公共DNS作为 dnsmasq 的上游
if [ -z "$DHCP_DNS_SERVERS" ]; then
log_message "No DHCP-assigned DNS found or interface not active, falling back to public DNS for dnsmasq upstreams."
DHCP_DNS_SERVERS="1.1.1.1 8.8.8.8" # 你可以自定义这些公共DNS服务器
fi

# 生成dnsmasq的上游配置文件
echo "# Generated by audo_update_dns.sh on $(date)" | sudo tee "$DNSMASQ_UPSTREAMS_FILE" > /dev/null
for dns_ip in $DHCP_DNS_SERVERS; do
echo "nameserver $dns_ip" | sudo tee -a "$DNSMASQ_UPSTREAMS_FILE" > /dev/null
done
log_message "Generated dnsmasq upstream file: $DNSMASQ_UPSTREAMS_FILE"

sudo networksetup -setdnsservers "$WIFI_SERVICE" 127.0.0.1

sudo brew services restart dnsmasq

关于MacOS的自启动项目

分为系统级的和用户级的,系统级的在/System/Library下,用户级的自启动项目在/Library/LaunchDaemons,以.plist结尾。launchDaemons可以翻译为守护进程,这个目录下还有一个LaunchAgents,可以理解为代理进程

目录 用途 加载场景
/System/Library/LaunchDaemons 系统级别的守护进程 系统启动
/System/Library/LaunchAgents 系统级别的代理进程 系统启动
/Library/LaunchDaemons 第三方系统守护进程 用户登录
/Library/LaunchAgents 适用所有用户的第三方代理进程 用户登录
~/Library/LaunchAgents 仅适用当前登录用户的第三方代理 用户登录
注意理解LaunchDaemonsLaunchAgents这俩机制的区别,主要在运行上下文和运行权限
  • LaunchAgents是以当前登录用户的身份运行的,LaunchAgents启动的进程称为代理进程,通常运行在用户空间,权限较低,只能访问当前用户的资源。它们往往会和GUI界面相关联,例如某些应用程序的自启动
  • LaunchDaemons是以root用户或指定系统用户身份运行的,LaunchDaemons启动的进程称为守护进程,通常运行在系统空间,权限较高。往往是一些后台任务,没有UI界面,例如系统服务,网络服务等。守护进程和服务由launchd分别在两个独立上下文中启动
    image.png

用brew安装的包可以用 brew services start xxx 来将其设置为自启动,例如:

1
brew services start dnsmasq

通过这种方式设置的自启动项目会自动生成一个.plist文件,根据其运行权限,如果是以某个用户身份执行,这个.plist文件会在~/Library/LaunchAgents,如果是以系统级别运行,则会出现在/Library/LaunchDaemons,以上面dnsmasq为例,dnsmasq需要以系统权限运行,因此在/Library/LaunchDaemons可以看到homebrew.mxcl.dnsmasq.plist文件,其内容如下:

fold
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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<?KeepAlive=true表示进程停止后再次启动?>
<key>KeepAlive</key>
<true/>
<?Label是进程唯一标识?>
<key>Label</key>
<string>homebrew.mxcl.dnsmasq</string>
<?LimitLoadToSessionType?>
<key>LimitLoadToSessionType</key>
<array>
<string>Aqua</string>
<string>Background</string>
<string>LoginWindow</string>
<string>StandardIO</string>
<string>System</string>
</array>
<?ProgramArguments 进程启动的执行参数?>
<key>ProgramArguments</key>
<array>
<string>/usr/local/opt/dnsmasq/sbin/dnsmasq</string>
<string>--keep-in-foreground</string>
<string>-C</string>
<string>/usr/local/etc/dnsmasq.conf</string>
<string>-7</string>
<string>/usr/local/etc/dnsmasq.d,*.conf</string>
</array>
<?加载时启动?>
<key>RunAtLoad</key>
<true/>
<?环境变量配置?>
<key>EnvironmentVariables</key>
<dict></dict>
<?WorkingDirectory 指定工作目录?>
<?StandardErrorPath 标准错误输出 StandardOutPath 标准输出?>
<??>
</dict>
</plist>

mac用launchctl来管理守护进程和代理,避免直接交互launchdlaunchctl能够加载/卸载/启动由launchd启动的守护进程和代理进程

1
2
3
4
5
6
7
# xxx是在.plist文件中定义的label 或 文件名
launchctl list # 查看所有启动脚本
launchctl load # 加载一个启动项
launchctl unload # 卸载
launchctl start # 运行
launchctl stop # 停止
launchctl remove xxx.plist # 移除启动项

将nginx-ui 和 dnsmasq配置为开机自启动

由于dnsmasq是由brew管理,通过brew运行时已经自动配置为自启动。下面看nginx-ui的自启动配置。
nginx的启动一般也是系统级别的,因此我们在/Library/LaunchDaemons目录下自定义一个com.nginx.startup.plist,内容如下:

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nginx.startup</string>

<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>

<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>~/app/nginx-ui/startup.sh</string>
</array>

<key>RunAtLoad</key>
<true/>

<key>KeepAlive</key>
<true/>

<key>StandardErrorPath</key>
<string>~/app/nginx-ui/error.log</string>

<key>StandardOutPath</key>
<string>~/app/nginx-ui/access.log</string>
</dict>
</plist>

其中nginx-ui/startup.sh内包含nginx-ui启动命令:

1
2
cd "$(dirname "$0")"
./nginx-ui -config app.ini

dnsmasq.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
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
#no-hosts

# 添加读取额外的 hosts 文件路径,可以多次指定。如果指定为目录,则读取目录中的所有文件。

#addn-hosts=/etc/dnsmasq.hosts.d

# 读取目录中的所有文件,文件更新将自动读取

#hostsdir=/etc/dnsmasq.hosts.d

# 例如,/etc/hosts中的os01将扩展成os01.example.com

#expand-hosts

##########################################################################

# 缓存时间设置,一般不需要设置

# 本地 hosts 文件的缓存时间,通常不要求缓存本地,这样更改hosts文件后就即时生效。

#local-ttl=3600

# 同 local-ttl 仅影响 DHCP 租约

#dhcp-ttl=<time>

# 对于上游返回的值没有ttl时,dnsmasq给一个默认的ttl,一般不需要设置,

#neg-ttl=<time>

# 指定返回给客户端的ttl时间,一般不需要设置

#max-ttl=<time>

# 设置在缓存中的条目的最大 TTL。

#max-cache-ttl=<time>

# 不需要设置,除非你知道你在做什么。

#min-cache-ttl=<time>

# 一般不需要设置

#auth-ttl=<time>



##############################################################################

# 记录dns查询日志,如果指定 log-queries=extra 那么在每行开始处都有额外的日志信息。

#log-queries

# 设置日志记录器,'-'stderr,也可以是文件路径。默认为:DAEMON,调试时使用 LOCAL0。

#log-facility=<facility>

#log-facility=/var/log/dnsmasq/dnsmasq.log

# 异步log,缓解阻塞,提高性能。默认为5,最大100

#log-async[=<lines>]

#log-async=50



##############################################################################

# 指定用户和组

#user=nobody

#group=nobody



##############################################################################

# 指定DNS的端口,默认53,设置 port=0 将完全禁用 DNS 功能,仅使用 DHCP/TFTP

#port=53

# 指定 EDNS.0 UDP 包的最大尺寸,默认为 RFC5625 推荐的 edns-packet-max=4096

#edns-packet-max=<size>

# 指定向上游查询的 UDP 端口,默认是随机端口,指定后降低安全性、加快速度、减少资源消耗。

# 设置为 '0' 由操作系统分配。

#query-port=53535

# 指定向上游查询的 UDP 端口范围,方便防火墙设置。

#min-port=<port>

#max-port=<port>

# 指定接口,指定后同时附加 lo 接口,可以使用'*'通配符。

# 不能使用接口别名(例如:"eth1:0"),请用 listen-address 选项替代。

#interface=wlp2s0

# 指定排除的接口,排除优先级高,可以使用'*'通配符

#except-interface=

# 仅接受同一子网的 DNS 请求。

# 仅在未指定 interface、except-interface、listen-address 或者 auth-server 时有效。

#local-service

# 指定不提供 DHCP 或 TFTP 服务的接口,仅提供 DNS 服务。

#no-dhcp-interface=enp3s0

# 指定IP地址,可以多次指定。

# interface 选项和 listen-address 选项可以同时使用。

# 下面两行与指定 interface 选项的作用类似。

listen-address=192.168.10.17

#listen-address=127.0.0.1

# 通常情况下即使设置了 interface 选项(例如:interface=wlp2s0 )

# 将仍然绑定到通配符地址(例如:*:53 )。

# 开启此项将仅监听指定的接口。

# 适用于在同一主机的不同接口或 IP 地址上运行多个 dns 服务器。

bind-interfaces

# 对于新添加的接口不进行绑定。仅 Linux 系统支持,其他系统等同于 bind-interfaces 选项。

#bind-dynamic



##############################################################################

# 如果 hosts 中的主机有多个 IP 地址,仅返回对应子网的 IP 地址。

localise-queries

# 如果反向查找的是私有地址例如192.168.X.X,仅从 hosts 文件查找,不再转发到上游服务器

#bogus-priv

# 对于任何被解析到此 IP 的域名,将响应 NXDOMAIN 使其解析失效,可以多次指定

# 通常用于对于访问不存在的域名,禁止其跳转到运营商的广告站点。

#bogus-nxdomain=64.94.110.11

# 忽略包含指定地址的 A 记录查询的回复。

# 例如上游有台 dns 服务器伪造 www.baidu.com 的 IP 为 1.1.1.1 并且响应速度非常快。

# 指定 ignore-address=1.1.1.1 可以忽略它的响应信息,

# 从而等待 www.baidu.com 正确的查询结果。

#ignore-address=<ipaddr>

filterwin2k



##############################################################################

# 指定 resolv-file 文件路径,默认/etc/resolv.conf

#resolv-file=/etc/resolv.conf

# 不读取 resolv-file 来确定上游服务器

#no-resolv

# 在编译时需要启用 DBus 支持。

#enable-dbus[=<service-name>]

# 严格按照resolv.conf中的顺序进行查找

#strict-order

# 向所有上游服务器发送查询,而不是一个。

all-servers

# 启用转发循环检测

#dns-loop-detect



##############################################################################

# 这项安全设置是拒绝解析包含私有 IP 地址的域名,

# 这些IP地址包括如下私有地址范围:10.0.0.0/8172.16.0.0/12192.168.0.0/16

# 其初衷是要防止类似上游DNS服务器故意将某些域名解析成特定私有内网IP而劫持用户这样的安全***。

# 直接在配置文件中注销 stop-dns-rebind 配置项从而禁用该功能。

# 这个方法确实可以一劳永逸的解决解析内网 IP 地址的问题,

# 但是我们也失去了这项安全保护的特性,所以在这里我不推荐这个办法。

# 使用 rebind-domain-ok 进行特定配置,顾名思义该配置项可以有选择的忽略域名的 rebind 行为

stop-dns-rebind

rebind-localhost-ok

#rebind-domain-ok=[<domain>]|[[/<domain>/[<domain>/]

rebind-domain-ok=/.test.com/



##############################################################################

# 也不要检测 /etc/resolv.conf 的变化

#no-poll

# 重启后清空缓存

clear-on-reload

# 完整的域名才向上游服务器查找,如果仅仅是主机名仅查找hosts文件

domain-needed



##############################################################################

# IP地址转换

#alias=[<old-ip>]|[<start-ip>-<end-ip>],<new-ip>[,<mask>]

##############################################################################

#local=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]

#server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]

server=/test.com/192.168.10.117

server=/10.168.192.in-addr.arpa/192.168.10.117

#rev-server=<ip-address>/<prefix-len>,<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]



# 将任何属于 <domain> 域名解析成指定的 <ipaddr> 地址。

# 也就是将 <domain> 及其所有子域名解析成指定的 <ipaddr> IPv4 或者 IPv6 地址,通常用于屏蔽特定的域名。

# 一次只能指定一个 IPv4 或者 IPv6 地址,要同时返回 IPv4 和IPv6 地址,请多次指定 address= 选项。

# 注意: /etc/hosts 以及 DHCP 租约将覆盖此项设置。

#address=/<domain>/[domain/][<ipaddr>]



#ipset=/<domain>/[domain/]<ipset>[,<ipset>]

#mx-host=<mx name>[[,<hostname>],<preference>]

#mx-target=<hostname>



# SRV 记录

#srv-host=<_service>.<_prot>.[<domain>],[<target>[,<port>[,<priority>[,<weight>]]]]



# A, AAAA 和 PTR 记录

#host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6-address>][,<TTL>]



# TXT 记录

#txt-record=<name>[[,<text>],<text>]



# PTR 记录

#ptr-record=<name>[,<target>]



#naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]



# CNAME 别名记录

#cname=<cname>,<target>[,<TTL>]





#dns-rr=<name>,<RR-number>,[<hex data>]

#interface-name=<name>,<interface>[/4|/6]

#synth-domain=<domain>,<address range>[,<prefix>]

#add-mac[=base64|text]

#add-cpe-id=<string>

#add-subnet[[=[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6 address>/]<IPv6 prefix length>]]

##############################################################################



##############################################################################

# 缓存条数,默认为150条,cache-size=0 禁用缓存。

cache-size=1000

# 不缓存未知域名缓存,默认情况下dnsmasq缓存未知域名并直接返回为客户端。

no-negcache

# 指定DNS同属查询转发数量

dns-forward-max=1000



##############################################################################

#dnssec

#trust-anchor=[<class>],<domain>,<key-tag>,<algorithm>,<digest-type>,<digest>

#dnssec-check-unsigned

#dnssec-no-timecheck

#dnssec-timestamp=<path>

#proxy-dnssec

#dnssec-debug



##############################################################################

#auth-server=<domain>,<interface>|<ip-address>

#auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....]]

#auth-zone=<domain>[,<interface name>[/6|/4][,<interface name>[/6|/4].....]]

#auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]]

#auth-sec-servers=<domain>[,<domain>[,<domain>...]]

#auth-peer=<ip-address>[,<ip-address>[,<ip-address>...]]



# 启用连接跟踪,读取 Linux 入栈 DNS 查询请求的连接跟踪标记,

# 并且将上游返回的响应信息设置同样的标记。

# 用于带宽控制和防火墙部署。

# 此选项必须在编译时启用 conntrack 支持,并且内核正确配置并加载 conntrack。

# 此选项不能与 query-port 同时使用。

#conntrack





##############################################################################

#

# DHCP 选项

#

##############################################################################

# 设置 DHCP 地址池,同时启用 DHCP 功能。

# IPv4 <mode> 可指定为 static|proxy ,当 <mode> 指定为 static 时,

# 需用 dhcp-host 手动分配地址池中的 IP 地址。

# 当 <mode> 指定为 proxy 时,为指定的地址池提供 DHCP 代理。

#dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>][,<mode>][,<netmask>[,<broadcast>]][,<lease time>]

#dhcp-range=172.16.0.2,172.16.0.250,255.255.255.0,1h

#dhcp-range=192.168.10.150,192.168.10.180,static,255.255.255.0,1h



# 根据 MAC 地址或 id 固定分配客户端的 IP 地址、主机名、租期。

# IPv4 下指定 id:* 将忽略 DHCP 客户端的 ID ,仅根据 MAC 来进行 IP 地址分配。

# 在读取 /etc/hosts 的情况,也可以根据 /etc/hosts 中的主机名分配对应 IP 地址。

# 指定 ignore 将忽略指定客户端得 DHCP 请求。

#dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]

#dhcp-hostsfile=<path>

#dhcp-hostsdir=<path>

# 读取 /etc/ethers 文件 与使用 dhcp-host 的作用相同。IPv6 无效。

#read-ethers



# 指定给 DHCP 客户端的选项信息,

# 默认情况下 dnsmasq 将发送:子网掩码、广播地址、DNS 服务器地址、网关地址、域等信息。

# 指定此选项也可覆盖这些默认值并且设置其他选项值。

# 重要:可以使用 option:<option-name>或者 option号 来指定。

# <option-name> 和 option号的对应关系可使用命令:

# dnsmasq --help dhcp 以及 dnsmasq --help dhcp6 查看,这点很重要。

# 例如设置网关参数,既可以使用 dhcp-option=3,192.168.4.4 也可以使用 dhcp-option = option:router,192.168.4.4

# 0.0.0.0 意味着当前运行 dnsmasq 的主机地址。

# 如果指定了多个 tag:<tag> 必须同时匹配才行。

# [encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],] 有待继续研究。

#dhcp-option=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>|option6:<opt>|option6:<opt-name>],[<value>[,<value>]]

#dhcp-option-force=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],]<opt>,[<value>[,<value>]]

#dhcp-optsfile=<path>

#dhcp-optsdir=<path>

#dhcp-option=3,1.2.3.4

#dhcp-option=option:router,1.2.3.4

#dhcp-option=option:router,192.168.10.254

#dhcp-option=option:dns-server,192.168.10.254,221.12.1.227,221.12.33.227



##############################################################################

# (IPv4 only) 禁用重用服务器名称和文件字段作为额外的 dhcp-option 选项。

# 一般情况下 dnsmasq 从 dhcp-boot 移出启动服务器和文件信息到 dhcp-option 选项中。

# 这使得在 dhcp-option 选项封包中有额外的选项空间可用,但是会使老的客户端混淆。

# 此选项将强制使用简单并安全的方式来避免此类情况。可以认为是一个兼容性选项。

#dhcp-no-override



##############################################################################

# 配置 DHCP 中继。

# <local address> 是运行 dnsmasq 的接口的 IP 地址。

# 所有在 <local address> 接口上接收到的 DHCP 请求将中继到 <server address> 指定的远程 DHCP 服务器。

# 可以多次配置此选项,使用同一个 <local address> 转发到多个不同的 <server address> 指定的远程 DHCP 服务器。

# <server address> 仅允许使用 IP 地址,不能使用域名等其他格式。

# 如果是 DHCPv6,<server address> 可以是 ALL_SERVERS 的多播地址 ff05::1:3

# 在这种情况下必须指定接口 <interface> ,不能使用通配符,用于直接多播到对应的 DHCP 服务器所在的接口。

# <interface> 指定了仅允许接收从 <interface> 接口的 DHCP 服务器相应信息。

#dhcp-relay=<local address>,<server address>[,<interface>]



##############################################################################

# 设置标签

#dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>

#dhcp-userclass=set:<tag>,<user-class>

#dhcp-mac=set:<tag>,<MAC address>

#dhcp-circuitid=set:<tag>,<circuit-id>

#dhcp-remoteid=set:<tag>,<remote-id>

#dhcp-subscrid=set:<tag>,<subscriber-id>

#dhcp-match=set:<tag>,<option number>|option:<option name>|vi-encap:<enterprise>[,<value>]

#tag-if=set:<tag>[,set:<tag>[,tag:<tag>[,tag:<tag>]]]



#dhcp-proxy[=<ip addr>]......



##############################################################################

# 不分配匹配这些 tag:<tag> 的 DHCP 请求。

#dhcp-ignore=tag:<tag>[,tag:<tag>]

#dhcp-ignore-names[=tag:<tag>[,tag:<tag>]]

#dhcp-generate-names=tag:<tag>[,tag:<tag>]

# IPv4 only 使用广播与匹配 tag:<tag> 的客户端通信。一般用于兼容老的 BOOT 客户端。

#dhcp-broadcast[=tag:<tag>[,tag:<tag>]]



##############################################################################

# IPv4 only 设置 DHCP 服务器返回的 BOOTP 选项,

# <servername> <server address> 可选,

# 如果未设置服务器名称将设为空,服务器地址设为 dnsmasq 的 IP 地址。

# 如果指定了多个 tag:<tag> 必须同时匹配才行。

# 如果指定 <tftp_servername> 将按照 /etc/hosts 中对应的 IP 地址进行轮询负载均衡。

#dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]

# 根据不同的类型使用不同的选项。

# 使用示例:

# dhcp-match=set:EFI_x86-64,option:client-arch,9

# dhcp-boot=tag:EFI_x86-64,uefi/grubx64.efi

# #dhcp-match=set:EFI_Xscale,option:client-arch,8

# #dhcp-boot=tag:EFI_Xscale,uefi/grubx64.efi

# #dhcp-match=set:EFI_BC,option:client-arch,7

# #dhcp-boot=tag:EFI_BC,uefi/grubx64.efi

# #dhcp-match=set:EFI_IA32,option:client-arch,6

# #dhcp-boot=tag:EFI_IA32,uefi/grubx64.efi

# #dhcp-match=set:Intel_Lean_Client,option:client-arch,5

# #dhcp-boot=tag:Intel_Lean_Client,uefi/grubx64.efi

# #dhcp-match=set:Arc_x86,option:client-arch,4

# #dhcp-boot=tag:Arc_x86,uefi/grubx64.efi

# #dhcp-match=set:DEC_Alpha,option:client-arch,3

# #dhcp-boot=tag:DEC_Alpha,uefi/grubx64.efi

# #dhcp-match=set:EFI_Itanium,option:client-arch,2

# #dhcp-boot=tag:EFI_Itanium,uefi/grubx64.efi

# #dhcp-match=set:NEC/PC98,option:client-arch,1

# #dhcp-boot=tag:NEC/PC98,uefi/grubx64.efi

# dhcp-match=set:Intel_x86PC,option:client-arch,0

# dhcp-boot=tag:Intel_x86PC,pxelinux.0



##############################################################################

# DHCP 使用客户端的 MAC 地址的哈希值为客户端分配 IP 地址,

# 通常情况下即使客户端使自己的租约到期,客户端的 IP 地址仍将长期保持稳定。

# 在默认模式下,IP 地址是随机分配的。

# 启用 dhcp-sequential-ip 选项将按顺序分配 IP 地址。

# 在顺序分配模式下,客户端使租约到期更像是仅仅移动一下 IP 地址。

# 在通常情况下不建议使用这种方式。

#dhcp-sequential-ip



##############################################################################

# 多数情况下我们使用 PXE,只是简单的允许 PXE 客户端获取 IP 地址,

# 然后 PXE 客户端下载 dhcp-boot 选项指定的文件并执行,也就是 BOOTP 的方式。

# 然而在有适当配置的 DHCP 服务器支持的情况下,PXE 系统能够实现更复杂的功能。

# pxe-service 选项可指定 PXE 环境的启动菜单。

# 为不同的类型系统设定不同的启动菜单,并且覆盖 dhcp-boot 选项。

# <CSA> 为客户端系统类型:x86PC, PC98, IA64_EFI, Alpha, Arc_x86, Intel_Lean_Client,

# IA32_EFI, X86-64_EFI, Xscale_EFI, BC_EFI, ARM32_EFI 和 ARM64_EFI,其他类型可能为一个整数。

# <basename> 引导 PXE 客户端使用 tftp 从 <server address> 或者 <server_name> 下载文件。

# 注意:"layer" 后缀 (通常是 ".0") 由 PXE 提供,也就是 PXE 客户端默认在文件名附加 .0 后缀。

# 示例:pxe-service=x86PC, "Install Linux", pxelinux (读取 pxelinux.0 文件并执行)

# pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4(不适用于老的PXE)

# <bootservicetype> 整数,PXE 客户端将通过广播或者通过 <server address>

# 或者 <server_name> 搜索对应类型的适合的启动服务。。

# 示例:pxe-service=x86PC, "Install windows from RIS server", 1

# pxe-service=x86PC, "Install windows from RIS server", 1, 1.2.3.4

# 未指定 <basename>、<bootservicetype> 或者 <bootservicetype> 为 “0”,将从本地启动。

# 示例:pxe-service=x86PC, "Boot from local disk"

# pxe-service=x86PC, "Boot from local disk", 0

# 如果指定 <server_name> 将按照 /etc/hosts 中对应的 IP 地址进行轮询负载均衡。

#pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>|<server_name>]

# 在 PXE 启动后弹出提示,<prompt> 为提示内容,<timeout> 为超时时间,为 0 则立即执行。

# 如果未指定此选项,在有多个启动选项的情况下等待用户选择,不会超时。

#pxe-prompt=[tag:<tag>,]<prompt>[,<timeout>]

# 根据不同的类型使用不同的菜单,使用示例:

# #pxe-prompt="What system shall I netboot?", 120

# # or with timeout before first available action is taken:

# pxe-prompt="Press F8 or Enter key for menu.", 60

# pxe-service=x86PC, "Now in x86PC (BIOS mode), boot from local", 0

# pxe-service=x86PC, "Now in x86PC (BIOS mode)", pxelinux

# pxe-service=PC98, "Now in PC98 mode", PC98

# pxe-service=IA64_EFI, "Now in IA64_EFI mode", IA64_EFI

# pxe-service=Alpha, "Now in Alpha mode", Alpha

# pxe-service=Arc_x86, "Now in Arc_x86 mode", Arc_x86

# pxe-service=Intel_Lean_Client, "Now in Intel_Lean_Client mode", Intel_Lean_Client

# pxe-service=IA32_EFI, "Now in IA32_EFI mode", IA32_EFI

# pxe-service=X86-64_EFI, "Now in X86-64_EFI (UEFI mode), boot from local", 0

# pxe-service=X86-64_EFI, "Now in X86-64_EFI (UEFI mode)", grub/grub-x86_64.efi

# pxe-service=Xscale_EFI, "Now in Xscale_EFI mode", Xscale_EFI

# pxe-service=BC_EFI, "Now in BC_EFI mode", BC_EFI

# # CentOS7 系统不支持下列两个选项

# #pxe-service=ARM32_EFI,"Now in ARM32_EFI mode",ARM32_EFI

# #pxe-service=ARM64_EFI,"Now in ARM64_EFI mode",ARM64_EFI



##############################################################################

# 默认为150,即最多分配150个ip地址出去,最大1000个ip

#dhcp-lease-max=150

# (IPv4 only) 指定DHCP端口,默认为6768。如果不指定则为10671068,单指定一个,第二个加1

#dhcp-alternate-port[=<server port>[,<client port>]]

# 谨慎使用此选项,避免 IP 地址浪费。(IPv4 only) 允许动态分配 IP 地址给 BOOTP 客户端。

# 注意:BOOTP 客户端获取的 IP 地址是永久的,将无法再次分配给其他客户端。

#bootp-dynamic[=<network-id>[,<network-id>]]

# 谨慎使用此选项。

# 默认情况下 DHCP 服务器使用 ping 的方式进行确保 IP 未被使用的情况下将 IP 地址分配出去。

# 启用此选项将不使用 ping 进行确认。

#no-ping



##############################################################################

# 记录额外的 dhcp 日志,记录所有发送给 DHCP 客户端的选项(option)以及标签(tag)信息

#log-dhcp

# 禁止记录日常操作日志,错误日志仍然记录。启用 log-dhcp 将覆盖下列选项。

#quiet-dhcp

#quiet-dhcp6

#quiet-ra



# 修改 DHCP 默认租约文件路径,默认情况下无需修改

#dhcp-leasefile=/var/lib/dnsmasq/dnsmasq.leases

# (IPv6 only)

#dhcp-duid=<enterprise-id>,<uid>



##############################################################################

#dhcp-script=<path>

#dhcp-luascript=<path>

#dhcp-scriptuser=root

#script-arp

#leasefile-ro



#bridge-interface=<interface>,<alias>[,<alias>]



##############################################################################

# 给 DHCP 服务器指定 domain 域名信息,也可以给对应的 IP 地址池指定域名。

# 直接指定域名

# 示例:domain=thekelleys.org.uk

# 子网对应的域名

# 示例:domain=wireless.thekelleys.org.uk,192.168.2.0/24

# ip范围对应的域名

# 示例:domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200

#domain=<domain>[,<address range>[,local]]

# 在默认情况下 dnsmasq 插入普通的客户端主机名到 DNS 中。

# 在这种情况下主机名必须唯一,即使两个客户端具有不同的域名后缀。

# 如果第二个客户端使用了相同的主机名,DNS 查询将自动更新为第二个客户端的 IP 地址。

# 如果设置了 dhcp-fqdn 选项,普通的主机名将不再插入到 DNS 中去,

# 仅允许合格的具有域名后缀的主机名插入到 DNS 服务器中。

# 指定此选项需同时指定不含 <address range> 地址范围的 domain 选项。

#dhcp-fqdn

# 通常情况下分配 DHCP 租约后,dnsmasq 设置 FQDN 选项告诉客户端不要尝试 DDNS 更新主机名与 IP 地址。

# 这是因为 name-IP 已自动添加到 dnsmasq 的 DNS 视图中的。

# 设置此选项将允许客户端 DDNS 更新,

# 在 windows 下允许客户端更新 windows AD 服务器是非常有用的。

# 参看 RFC 4702

#dhcp-client-update



#enable-ra

#ra-param=<interface>,[high|low],[[<ra-interval>],<router lifetime>]





##############################################################################

#

# TFTP 选项

#

##############################################################################

# 对于绝大多数的配置,仅需指定 enable-tftp 和 tftp-root 选项即可。

# 是否启用内置的 tftp 服务器,可以指定多个逗号分隔的网络接口

#enable-tftp[=<interface>[,<interface>]]

#enable-tftp

#enable-tftp=enp3s0,lo

# 指定 tftp 的根目录,也就是寻找传输文件时使用的相对路径,可以附加接口,

#tftp-root=<directory>[,<interface>]

#tftp-root=/var/lib/tftpboot/

# 如果取消注释,那么即使指定的 tftp-root 无法访问,仍然启动 tftp 服务。

#tftp-no-fail

# 附加客户端的 IP 地址作为文件路径。此选项仅在正确设置了 tftp-root 的情况下可用,

# 示例:如果 tftp-root=/tftp,客户端为 192.168.1.15 请求 myfile.txt 文件时,

# 将优先请求 /tftp/192.168.1.15/myfile.txt 文件, 其次是 /tftp/myfile.txt 文件。

# 感觉没什么用。

#tftp-unique-root

# 启用安全模式,启用此选项,仅允许 tftp 进程访问属主为自己的文件。

# 不启用此选项,允许访问所有 tftp 进程属主可读取的文件。

# 如果 dnsmasq 是以 root 用户运行,tftp-secure 选项将允许访问全局可读的文件。

# 一般情况下不推荐以 root 用户运行 dnsmasq。

# 在指定了 tftp-root 的情况下并不是很重要。

#tftp-secure

# 将所有文件请求转换为小写。对于 Windows 客户端来说非常有用,建议开启此项。

# 注意:dnsmasq 的 TFTP 服务器总是将文件路径中的“\”转换为“/”。

#tftp-lowercase

# 允许最大的连接数,默认为 50

# 如果将连接数设置的很大,需注意每个进程的最大文件描述符限制,详见文档手册。

#tftp-max=<connections>

#tftp-max=50

# 设置传输时的 MTU 值,建议不设置或按需设置。

# 如果设定的值大于网络接口的 MTU 值,将按照网络接口的 MTU 值自动分片传输(不推荐)。

#tftp-mtu=<mtu size>

# 停止 tftp 服务器与客户端协商 "blocksize" 选项。启用后,防止一些古怪的客户端出问题。

#tftp-no-blocksize

# 指定 tftp 的连接端口的范围,方便防火墙部署。

# tftp 侦听在 69/udp ,连接端口默认是由系统自动分配的,

# 非 root 用户运行时指定的连接端口号需大于 1025 最大 65535

#tftp-port-range=<start>,<end>

###############################################################################

#conf-dir=<directory>[,<file-extension>......]

#conf-file=/etc/dnsmasq.more.conf

conf-dir=/etc/dnsmasq.d

#servers-file=<file>
其他文章