diff --git a/internal/web/actions/default/servers/certs/selectPopup.go b/internal/web/actions/default/servers/certs/selectPopup.go
index c6f446b4..54a9bb72 100644
--- a/internal/web/actions/default/servers/certs/selectPopup.go
+++ b/internal/web/actions/default/servers/certs/selectPopup.go
@@ -30,9 +30,10 @@ func (this *SelectPopupAction) RunGet(params struct {
 	// TODO 列出常用和最新的证书供用户选择
 
 	this.Data["keyword"] = params.Keyword
+	this.Data["selectedCertIds"] = params.SelectedCertIds
 
 	// 已经选择的证书
-	selectedCertIds := []string{}
+	var selectedCertIds = []string{}
 	if len(params.SelectedCertIds) > 0 {
 		selectedCertIds = strings.Split(params.SelectedCertIds, ",")
 	}
diff --git a/web/public/js/components.js b/web/public/js/components.js
index dac49b1e..413b3f95 100644
--- a/web/public/js/components.js
+++ b/web/public/js/components.js
@@ -1321,7 +1321,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
 			
 			
 			
-				| 是否开启HSTS | 
+				开启HSTS | 
 				
 					
 	
-`}),Vue.component("origin-list-box",{props:["v-primary-origins","v-backup-origins","v-server-type","v-params"],data:function(){return{primaryOrigins:this.vPrimaryOrigins,backupOrigins:this.vBackupOrigins}},methods:{createPrimaryOrigin:function(){teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&"+this.vParams,{height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},createBackupOrigin:function(){teaweb.popup("/servers/server/settings/origins/addPopup?originType=backup&"+this.vParams,{height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},updateOrigin:function(e,t){teaweb.popup("/servers/server/settings/origins/updatePopup?originType="+t+"&"+this.vParams+"&originId="+e,{height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},deleteOrigin:function(e,t){let i=this;teaweb.confirm("确定要删除此源站吗?",function(){Tea.action("/servers/server/settings/origins/delete?"+i.vParams+"&originId="+e+"&originType="+t).post().success(function(){teaweb.success("删除成功",function(){window.location.reload()})})})}},template:` 
+ `}),Vue.component("origin-list-box",{props:["v-primary-origins","v-backup-origins","v-server-type","v-params"],data:function(){return{primaryOrigins:this.vPrimaryOrigins,backupOrigins:this.vBackupOrigins}},methods:{createPrimaryOrigin:function(){teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&"+this.vParams,{width:"45em",height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},createBackupOrigin:function(){teaweb.popup("/servers/server/settings/origins/addPopup?originType=backup&"+this.vParams,{width:"45em",height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},updateOrigin:function(e,t){teaweb.popup("/servers/server/settings/origins/updatePopup?originType="+t+"&"+this.vParams+"&originId="+e,{width:"45em",height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},deleteOrigin:function(e,t){let i=this;teaweb.confirm("确定要删除此源站吗?",function(){Tea.action("/servers/server/settings/origins/delete?"+i.vParams+"&originId="+e+"&originType="+t).post().success(function(){teaweb.success("删除成功",function(){window.location.reload()})})})}},template:`
 	
 	
 	
@@ -2385,29 +2385,50 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
 		已启用 /  空连接次数:{{config.minAttempts}}次/分钟 / 封禁时间:{{config.timeoutSeconds}}秒  / 忽略局域网访问
 	
 	未启用
-  `}),Vue.component("domains-box",{props:["v-domains","name"],data:function(){let e=this.vDomains,t=(null==e&&(e=[]),"domainsJSON");return null!=this.name&&"string"==typeof this.name&&(t=this.name),{domains:e,isAdding:!1,addingDomain:"",realName:t}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingDomain.focus()},100)},confirm:function(){let t=this;if(this.addingDomain=this.addingDomain.replace(/\s/g,""),0==this.addingDomain.length)teaweb.warn("请输入要添加的域名",function(){t.$refs.addingDomain.focus()});else{if("~"==this.addingDomain[0]){var e=this.addingDomain.substring(1);try{new RegExp(e)}catch(e){return void teaweb.warn("正则表达式错误:"+e.message,function(){t.$refs.addingDomain.focus()})}}this.domains.push(this.addingDomain),this.cancel()}},remove:function(e){this.domains.$remove(e)},cancel:function(){this.isAdding=!1,this.addingDomain=""}},template:`
+ `}),Vue.component("domains-box",{props:["v-domains","name","v-support-wildcard"],data:function(){let e=this.vDomains,t=(null==e&&(e=[]),"domainsJSON"),i=(null!=this.name&&"string"==typeof this.name&&(t=this.name),!0);return"boolean"==typeof this.vSupportWildcard&&(i=this.vSupportWildcard),{domains:e,mode:"single",batchDomains:"",isAdding:!1,addingDomain:"",isEditing:!1,editingIndex:-1,realName:t,supportWildcard:i}},watch:{vSupportWildcard:function(e){"boolean"==typeof e&&(this.supportWildcard=e)},mode:function(e){let t=this;setTimeout(function(){"single"==e?null!=t.$refs.addingDomain&&t.$refs.addingDomain.focus():"batch"==e&&null!=t.$refs.batchDomains&&t.$refs.batchDomains.focus()},100)}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingDomain.focus()},100)},confirm:function(){if("batch"==this.mode)this.confirmBatch();else{let t=this;if(this.addingDomain=this.addingDomain.replace(/\s/g,""),0==this.addingDomain.length)teaweb.warn("请输入要添加的域名",function(){t.$refs.addingDomain.focus()});else{if(this.supportWildcard){if("~"==this.addingDomain[0]){var e=this.addingDomain.substring(1);try{new RegExp(e)}catch(e){return void teaweb.warn("正则表达式错误:"+e.message,function(){t.$refs.addingDomain.focus()})}}}else if(/[*~^]/.test(this.addingDomain))return void teaweb.warn("当前只支持添加普通域名,域名中不能含有特殊符号",function(){t.$refs.addingDomain.focus()});this.isEditing&&0<=this.editingIndex?this.domains[this.editingIndex]=this.addingDomain:this.domains.push(this.addingDomain),this.cancel(),this.change()}}},confirmBatch:function(){let e=this.batchDomains.split("\n"),i=[],s=this,n=!1;e.forEach(function(e){if(!n&&0!=e.length){if(s.supportWildcard){if("~"==e){var t=e.substring(1);try{new RegExp(t)}catch(e){return n=!0,void teaweb.warn("正则表达式错误:"+e.message,function(){s.$refs.batchDomains.focus()})}}}else if(/[*~^]/.test(e))return n=!0,void teaweb.warn("当前只支持添加普通域名,域名中不能含有特殊符号",function(){s.$refs.batchDomains.focus()});i.push(e)}}),n||(0==i.length?teaweb.warn("请输入要添加的域名",function(){s.$refs.batchDomains.focus()}):(i.forEach(function(e){s.domains.push(e)}),this.cancel(),this.change()))},edit:function(e){this.addingDomain=this.domains[e],this.isEditing=!0,this.editingIndex=e;let t=this;setTimeout(function(){t.$refs.addingDomain.focus()},50)},remove:function(e){this.domains.$remove(e),this.change()},cancel:function(){this.isAdding=!1,this.mode="single",this.batchDomains="",this.isEditing=!1,this.editingIndex=-1,this.addingDomain=""},change:function(){this.$emit("change",this.domains)}},template:`
 	
 	
-		 
+		
 			[正则]
 			[后缀]
 			[泛域名]
 			{{domain}}
-			  
+			
+				  
+				  
+			
+			
+				  
+				  
+			
 		
 		
 	
-	 
+	 
 	
@@ -3371,7 +3392,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
 		  - 耗时:{{formatCost(accessLog.requestTime)}} ms   ({{accessLog.humanTime}})
 		  
 	
- `});var punycode=new function(){this.utf16={decode:function(e){for(var t,i,s=[],n=0,o=e.length;n >>10&1023|55296)),t=56320|1023&t),i.push(String.fromCharCode(t))}return i.join("")}};var b=2147483647;function y(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function x(e,t,i){var s;for(e=i?Math.floor(e/700):e>>1,e+=Math.floor(e/t),s=0;455= 0x80");d.push(e.charCodeAt(s))}for(n=0Math.floor((b-v)/a))throw RangeError("punycode_overflow(1)");if(v+=r*a,r<(r=l<=m?1:m+26<=l?26:l-m))break;if(a>Math.floor(b/(36-r)))throw RangeError("punycode_overflow(2)");a*=36-r}if(m=x(v-o,i=d.length+1,0===o),Math.floor(v/i)>b-h)throw RangeError("punycode_overflow(3)");h+=Math.floor(v/i),v%=i,t&&p.splice(v,0,e.charCodeAt(n-1)-65<26),d.splice(v,0,h),v++}if(t)for(v=0,c=d.length;vMath.floor((b-m)/(i+1)))throw RangeError("punycode_overflow (1)");for(m+=(n-v)*(i+1),v=n,g=0;gb)return Error("punycode_overflow(2)");if(c==v){for(o=m,a=36;!(o<(l=a<=f?1:f+26<=a?26:a-f));a+=36)h.push(String.fromCharCode(y(l+(o-l)%(36-l),0))),o=Math.floor((o-l)/(36-l));h.push(String.fromCharCode(y(o,t&&r[g]?1:0))),f=x(m,i+1,i==s),m=0,++i}}++m,++v}return h.join("")},this.ToASCII=function(e){for(var t=e.split("."),i=[],s=0;s
+ `});var punycode=new function(){this.utf16={decode:function(e){for(var t,i,s=[],n=0,o=e.length;n>>10&1023|55296)),t=56320|1023&t),i.push(String.fromCharCode(t))}return i.join("")}};var b=2147483647;function y(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function x(e,t,i){var s;for(e=i?Math.floor(e/700):e>>1,e+=Math.floor(e/t),s=0;455= 0x80");d.push(e.charCodeAt(s))}for(n=0Math.floor((b-m)/a))throw RangeError("punycode_overflow(1)");if(m+=r*a,r<(r=l<=v?1:v+26<=l?26:l-v))break;if(a>Math.floor(b/(36-r)))throw RangeError("punycode_overflow(2)");a*=36-r}if(v=x(m-o,i=d.length+1,0===o),Math.floor(m/i)>b-h)throw RangeError("punycode_overflow(3)");h+=Math.floor(m/i),m%=i,t&&p.splice(m,0,e.charCodeAt(n-1)-65<26),d.splice(m,0,h),m++}if(t)for(m=0,c=d.length;mMath.floor((b-v)/(i+1)))throw RangeError("punycode_overflow (1)");for(v+=(n-m)*(i+1),m=n,g=0;gb)return Error("punycode_overflow(2)");if(c==m){for(o=v,a=36;!(o<(l=a<=f?1:f+26<=a?26:a-f));a+=36)h.push(String.fromCharCode(y(l+(o-l)%(36-l),0))),o=Math.floor((o-l)/(36-l));h.push(String.fromCharCode(y(o,t&&r[g]?1:0))),f=x(v,i+1,i==s),v=0,++i}}++v,++m}return h.join("")},this.ToASCII=function(e){for(var t=e.split("."),i=[],s=0;s
 	默认设置
 	
 		状态码:{{options.statusCode}} / 提示内容: [{{options.body.length}}字符][无]  / 超时时间:{{options.timeout}}秒
@@ -4826,7 +4847,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
 	 
 	
 		
-			 
+			 
 				{{addr.protocol}}://{{addr.host.quoteIP()}}:{{addr.portRange}}
 				 
 				
diff --git a/web/public/js/components.src.js b/web/public/js/components.src.js
index d49c5b61..91e32317 100755
--- a/web/public/js/components.src.js
+++ b/web/public/js/components.src.js
@@ -3980,7 +3980,7 @@ Vue.component("ssl-config-box", {
 			
 			
 			 
-				| 是否开启HSTS | 
+				开启HSTS | 
 				
 					
 						
@@ -6446,6 +6446,7 @@ Vue.component("origin-list-box", {
 	methods: {
 		createPrimaryOrigin: function () {
 			teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&" + this.vParams, {
+				width: "45em",
 				height: "27em",
 				callback: function (resp) {
 					teaweb.success("保存成功", function () {
@@ -6456,6 +6457,7 @@ Vue.component("origin-list-box", {
 		},
 		createBackupOrigin: function () {
 			teaweb.popup("/servers/server/settings/origins/addPopup?originType=backup&" + this.vParams, {
+				width: "45em",
 				height: "27em",
 				callback: function (resp) {
 					teaweb.success("保存成功", function () {
@@ -6466,6 +6468,7 @@ Vue.component("origin-list-box", {
 		},
 		updateOrigin: function (originId, originType) {
 			teaweb.popup("/servers/server/settings/origins/updatePopup?originType=" + originType + "&" + this.vParams + "&originId=" + originId, {
+				width: "45em",
 				height: "27em",
 				callback: function (resp) {
 					teaweb.success("保存成功", function () {
@@ -7045,7 +7048,7 @@ Vue.component("firewall-syn-flood-config-viewer", {
 
 // 域名列表
 Vue.component("domains-box", {
-	props: ["v-domains", "name"],
+	props: ["v-domains", "name", "v-support-wildcard"],
 	data: function () {
 		let domains = this.vDomains
 		if (domains == null) {
@@ -7056,11 +7059,47 @@ Vue.component("domains-box", {
 		if (this.name != null && typeof this.name == "string") {
 			realName = this.name
 		}
+
+		let supportWildcard = true
+		if (typeof this.vSupportWildcard == "boolean") {
+			supportWildcard = this.vSupportWildcard
+		}
+
 		return {
 			domains: domains,
+
+			mode: "single", // single | batch
+			batchDomains: "",
+
 			isAdding: false,
 			addingDomain: "",
-			realName: realName
+
+			isEditing: false,
+			editingIndex: -1,
+
+			realName: realName,
+			supportWildcard: supportWildcard
+		}
+	},
+	watch: {
+		vSupportWildcard: function (v) {
+			if (typeof v == "boolean") {
+				this.supportWildcard = v
+			}
+		},
+		mode: function (mode) {
+			let that = this
+			setTimeout(function () {
+				if (mode == "single") {
+					if (that.$refs.addingDomain != null) {
+						that.$refs.addingDomain.focus()
+					}
+				} else if (mode == "batch") {
+					if (that.$refs.batchDomains != null) {
+						that.$refs.batchDomains.focus()
+					}
+				}
+			}, 100)
 		}
 	},
 	methods: {
@@ -7072,6 +7111,11 @@ Vue.component("domains-box", {
 			}, 100)
 		},
 		confirm: function () {
+			if (this.mode == "batch") {
+				this.confirmBatch()
+				return
+			}
+
 			let that = this
 
 			// 删除其中的空格
@@ -7084,54 +7128,155 @@ Vue.component("domains-box", {
 				return
 			}
 
-
 			// 基本校验
-			if (this.addingDomain[0] == "~") {
-				let expr = this.addingDomain.substring(1)
-				try {
-					new RegExp(expr)
-				} catch (e) {
-					teaweb.warn("正则表达式错误:" + e.message, function () {
+			if (this.supportWildcard) {
+				if (this.addingDomain[0] == "~") {
+					let expr = this.addingDomain.substring(1)
+					try {
+						new RegExp(expr)
+					} catch (e) {
+						teaweb.warn("正则表达式错误:" + e.message, function () {
+							that.$refs.addingDomain.focus()
+						})
+						return
+					}
+				}
+			} else {
+				if (/[*~^]/.test(this.addingDomain)) {
+					teaweb.warn("当前只支持添加普通域名,域名中不能含有特殊符号", function () {
 						that.$refs.addingDomain.focus()
 					})
 					return
 				}
 			}
 
-			this.domains.push(this.addingDomain)
+			if (this.isEditing && this.editingIndex >= 0) {
+				this.domains[this.editingIndex] = this.addingDomain
+			} else {
+				this.domains.push(this.addingDomain)
+			}
 			this.cancel()
+			this.change()
+		},
+		confirmBatch: function () {
+			let domains = this.batchDomains.split("\n")
+			let realDomains = []
+			let that = this
+			let hasProblems = false
+			domains.forEach(function (domain) {
+				if (hasProblems) {
+					return
+				}
+				if (domain.length == 0) {
+					return
+				}
+				if (that.supportWildcard) {
+					if (domain == "~") {
+						let expr = domain.substring(1)
+						try {
+							new RegExp(expr)
+						} catch (e) {
+							hasProblems = true
+							teaweb.warn("正则表达式错误:" + e.message, function () {
+								that.$refs.batchDomains.focus()
+							})
+							return
+						}
+					}
+				} else {
+					if (/[*~^]/.test(domain)) {
+						hasProblems = true
+						teaweb.warn("当前只支持添加普通域名,域名中不能含有特殊符号", function () {
+							that.$refs.batchDomains.focus()
+						})
+						return
+					}
+				}
+				realDomains.push(domain)
+			})
+			if (hasProblems) {
+				return
+			}
+			if (realDomains.length == 0) {
+				teaweb.warn("请输入要添加的域名", function () {
+					that.$refs.batchDomains.focus()
+				})
+				return
+			}
+
+			realDomains.forEach(function (domain) {
+				that.domains.push(domain)
+			})
+			this.cancel()
+			this.change()
+		},
+		edit: function (index) {
+			this.addingDomain = this.domains[index]
+			this.isEditing = true
+			this.editingIndex = index
+			let that = this
+			setTimeout(function () {
+				that.$refs.addingDomain.focus()
+			}, 50)
 		},
 		remove: function (index) {
 			this.domains.$remove(index)
+			this.change()
 		},
 		cancel: function () {
 			this.isAdding = false
+			this.mode = "single"
+			this.batchDomains = ""
+			this.isEditing = false
+			this.editingIndex = -1
 			this.addingDomain = ""
+		},
+		change: function () {
+			this.$emit("change", this.domains)
 		}
 	},
 	template: ` 
 	
 	
-		 
+		
 			[正则]
 			[后缀]
 			[泛域名]
 			{{domain}}
-			  
+			
+				  
+				  
+			
+			
+				  
+				  
+			
 		
 		
 	
-	 
+	 
 	
@@ -13798,7 +13943,7 @@ Vue.component("api-node-addresses-box", {
 	 
 	
 		
-			 
+			 
 				{{addr.protocol}}://{{addr.host.quoteIP()}}:{{addr.portRange}}
 				 
 				
diff --git a/web/public/js/components/server/ssl-config-box.js b/web/public/js/components/server/ssl-config-box.js
index 3691f2fc..42e9a738 100644
--- a/web/public/js/components/server/ssl-config-box.js
+++ b/web/public/js/components/server/ssl-config-box.js
@@ -416,7 +416,7 @@ Vue.component("ssl-config-box", {
 			
 			
 			 
-				| 是否开启HSTS | 
+				开启HSTS | 
 				
 					
 						
diff --git a/web/views/@default/servers/certs/selectPopup.html b/web/views/@default/servers/certs/selectPopup.html
index 15e58bd2..2deb1d91 100644
--- a/web/views/@default/servers/certs/selectPopup.html
+++ b/web/views/@default/servers/certs/selectPopup.html
@@ -4,12 +4,14 @@
 
 
  
@@ -18,14 +20,14 @@
 
  
 	
-	
-		| 证书说明 | 
-		域名 | 
-		过期日期 | 
-		引用服务 | 
-		状态 | 
-		操作 | 
-	 
+        
+            | 证书说明 | 
+            域名 | 
+            过期日期 | 
+            引用服务 | 
+            状态 | 
+            操作 | 
+         
 	
 	
         | 
@@ -42,7 +44,7 @@
 		 | 
 		
 			 
-                {{dnsName}}
+                {{dnsName}}
 			 
 		 | 
 		{{certInfos[index].endDay}} | 
    |      |    |