');mask-image:url('data:image/svg+xml, ')}.atk-icon-no:after,.atk-icon-close:after{-webkit-mask-image:url('data:image/svg+xml, ');mask-image:url('data:image/svg+xml, ')}.atk-error-layer{background-color:var(--at-color-bg-transl)}.atk-error-layer .atk-error-title{color:var(--at-color-red)}.atk-error-layer .atk-warn-title{color:var(--at-color-yellow)}.atk-error-layer .atk-error-title,.atk-error-layer .atk-warn-title{display:inline-block;padding:0 15px;margin-bottom:20px;font-size:20px;letter-spacing:-.5px}.atk-error-layer .atk-error-text{text-align:center;padding:0 20px}.atk-error-layer .atk-error-text *{color:var(--at-color-deep)}.atk-error-layer .atk-error-text a{color:var(--at-color-meta)}.atk-version-check-notice{background:var(--at-color-bg-grey);border-radius:6px;padding:10px 20px;margin-bottom:10px;font-size:14px}.atk-version-check-notice .atk-info{color:var(--at-color-meta)}.atk-version-check-notice .atk-ignore-btn{cursor:pointer;float:right}.atk-version-check-notice .atk-ignore-btn:hover{opacity:.8}.atk-layer-dialog-wrap{background-color:var(--at-color-bg-transl)}.atk-layer-dialog-wrap>.atk-layer-dialog{width:25%}.atk-layer-dialog-wrap>.atk-layer-dialog>.atk-layer-dialog-content .atk-captcha-img{cursor:pointer;width:170px;height:auto;margin-right:10px;padding-right:10px;border-right:1px solid var(--at-color-border);vertical-align:bottom}.atk-layer-dialog-wrap>.atk-layer-dialog>.atk-layer-dialog-content input{width:100%;line-height:34px;background-color:var(--at-color-bg);border:1px solid var(--at-color-border);border-radius:3px;outline:none;padding:0 6px;display:block;margin-top:10px;margin-bottom:5px;text-align:center}.atk-layer-dialog-wrap>.atk-layer-dialog>.atk-layer-dialog-actions{display:flex;flex-direction:row}.atk-layer-dialog-wrap>.atk-layer-dialog>.atk-layer-dialog-actions button{flex:1;display:block;cursor:pointer;border:1px solid var(--at-color-main);background:transparent;color:var(--at-color-main);border-radius:3px;padding:0 15px;line-height:30px;outline:none}.atk-layer-dialog-wrap>.atk-layer-dialog>.atk-layer-dialog-actions button:active{color:#fff;background:var(--at-color-main)}.atk-layer-dialog-wrap>.atk-layer-dialog>.atk-layer-dialog-actions button:not(:last-child){margin-right:5px}.atk-layer-dialog-wrap>.atk-layer-dialog>.atk-layer-dialog-actions button.error{color:#fff;background:#ff5652;border-color:#ff5652}.atk-layer-dialog-wrap>.atk-layer-dialog .atk-checker-iframe-wrap{position:fixed;z-index:999998;left:0;top:0;height:100vh;width:100vw}.atk-layer-dialog-wrap>.atk-layer-dialog .atk-checker-iframe-wrap>iframe{width:100%;height:100%;border:0}.atk-layer-dialog-wrap>.atk-layer-dialog .atk-checker-iframe-wrap .atk-close-btn{z-index:999999;position:fixed;top:20px;right:20px;display:flex;flex-direction:column;width:50px;height:50px;align-items:center;place-content:center;cursor:pointer;-webkit-user-select:none;user-select:none;margin-left:10px}.atk-layer-dialog-wrap>.atk-layer-dialog .atk-checker-iframe-wrap .atk-close-btn:hover .atk-icon-close:after{background-color:#e81123e6}@media only screen and (max-width: 768px){.atk-layer-dialog-wrap>.atk-layer-dialog{width:90%!important}}.atk-notify{display:block;overflow:hidden;background-color:#2c2c2c;color:#fff;border-radius:3px;cursor:pointer;font-size:14px;padding:5px 15px}.atk-notify:not(:last-child){margin-bottom:3px}.atk-notify .atk-notify-content{color:#fff}.atk-layer-wrap .atk-layer-mask{position:fixed;top:0;left:0;width:100%;height:100%;z-index:99998;background:#0000004d}.atk-layer-wrap .atk-layer-item{position:fixed;z-index:99999;top:0;right:0;width:100%;height:100%}.atk-common-action-btn.atk-btn-confirm,.atk-common-action-btn.atk-btn-warn{color:var(--at-color-yellow)!important}.atk-common-action-btn.atk-btn-error{color:var(--at-color-red)!important}.atk-common-action-btn.atk-btn-success{color:var(--at-color-green)!important}img[atk-emoticon]{max-height:60px;display:initial}.atk-slim-scrollbar::-webkit-scrollbar,.atk-editor-plug-emoticons>.atk-grp-wrap::-webkit-scrollbar{width:4px;height:4px;background:transparent}.atk-slim-scrollbar::-webkit-scrollbar-thumb,.atk-editor-plug-emoticons>.atk-grp-wrap::-webkit-scrollbar-thumb,.atk-slim-scrollbar::-webkit-scrollbar-thumb:window-inactive{background:#5656564d}.atk-slim-scrollbar::-webkit-scrollbar-thumb:vertical:hover,.atk-editor-plug-emoticons>.atk-grp-wrap::-webkit-scrollbar-thumb:vertical:hover{background:#414a52c4}.atk-slim-scrollbar::-webkit-scrollbar-thumb:vertical:active,.atk-editor-plug-emoticons>.atk-grp-wrap::-webkit-scrollbar-thumb:vertical:active{background:#292f35c4}.atk-editor-plug-emoticons{height:100%;width:100%}.atk-editor-plug-emoticons>.atk-grp-wrap{overflow-y:scroll;overflow-x:hidden;height:100%;width:100%}.atk-editor-plug-emoticons>.atk-grp-wrap>.atk-grp{display:flex;flex-wrap:wrap;flex-direction:row;padding:5px 10px 35px}.atk-editor-plug-emoticons>.atk-grp-wrap>.atk-grp[data-type=image]>.atk-item{height:63px;width:63px}.atk-editor-plug-emoticons>.atk-grp-wrap>.atk-grp>.atk-item{display:flex;align-items:center;justify-content:center;padding:5px;cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:3px;font-size:15px;min-width:35px;margin:2px}.atk-editor-plug-emoticons>.atk-grp-wrap>.atk-grp>.atk-item>img{max-height:100%;width:auto}.atk-editor-plug-emoticons>.atk-grp-wrap>.atk-grp>.atk-item:hover{background:var(--at-color-bg-grey)}.atk-editor-plug-emoticons>.atk-grp-switcher{position:absolute;bottom:0;left:0;width:100%;background:var(--at-color-bg-transl);height:30px;border-top:1px solid var(--at-color-border);border-bottom:1px solid var(--at-color-border)}.atk-editor-plug-emoticons>.atk-grp-switcher>span{-webkit-user-select:none;user-select:none;padding:0 10px;line-height:30px;float:left;display:block;cursor:pointer;font-size:14px}.atk-editor-plug-emoticons>.atk-grp-switcher>span:hover,.atk-editor-plug-emoticons>.atk-grp-switcher>span.active{background:var(--at-color-bg-grey)}.atk-slim-scrollbar::-webkit-scrollbar{width:4px;height:4px;background:transparent}.atk-slim-scrollbar::-webkit-scrollbar-thumb,.atk-slim-scrollbar::-webkit-scrollbar-thumb:window-inactive{background:#5656564d}.atk-slim-scrollbar::-webkit-scrollbar-thumb:vertical:hover{background:#414a52c4}.atk-slim-scrollbar::-webkit-scrollbar-thumb:vertical:active{background:#292f35c4}.atk-editor-plug-preview{overflow-y:scroll;overflow-x:hidden;height:100%;width:100%;padding:10px 15px}
code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:none;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#282a36}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:#6272a4}.token.punctuation{color:#f8f8f2}.namespace{opacity:.7}.token.property,.token.tag,.token.constant,.token.symbol,.token.deleted{color:#ff79c6}.token.boolean,.token.number{color:#bd93f9}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{color:#50fa7b}.token.operator,.token.entity,.token.url,.language-css .token.string,.style .token.string,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.function,.token.class-name{color:#f1fa8c}.token.keyword{color:#8be9fd}.token.regex,.token.important{color:#ffb86c}.token.important,.token.bold{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
/*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-font-weight:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-gray-200:oklch(92.8% .006 264.531);--color-gray-500:oklch(55.1% .027 264.364);--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5/2.25);--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--radius-sm:.25rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-blue:#3273dc}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);margin-top:1.2em;margin-bottom:1.2em;font-size:1.25em;line-height:1.6}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em;list-style-type:decimal}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em;list-style-type:disc}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.25em;font-weight:600}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em;font-style:italic;font-weight:500}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:0;margin-bottom:.888889em;font-size:2.25em;font-weight:800;line-height:1.11111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:2em;margin-bottom:1em;font-size:1.5em;font-weight:700;line-height:1.33333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.6em;margin-bottom:.6em;font-size:1.25em;font-weight:600;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.5em;margin-bottom:.5em;font-weight:600;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em;display:block}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px rgb(var(--tw-prose-kbd-shadows)/10%);padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;border-radius:.3125rem;padding-inline-start:.375em;font-family:inherit;font-size:.875em;font-weight:500}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);padding-top:.857143em;padding-inline-end:1.14286em;padding-bottom:.857143em;border-radius:.375rem;margin-top:1.71429em;margin-bottom:1.71429em;padding-inline-start:1.14286em;font-size:.875em;font-weight:400;line-height:1.71429;overflow-x:auto}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit;background-color:#0000;border-width:0;border-radius:0;padding:0}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){table-layout:auto;width:100%;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.71429}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);vertical-align:bottom;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em;font-weight:600}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);margin-top:.857143em;font-size:.875em;line-height:1.42857}.prose{--tw-prose-body:oklch(37.3% .034 259.733);--tw-prose-headings:oklch(21% .034 264.665);--tw-prose-lead:oklch(44.6% .03 256.802);--tw-prose-links:oklch(21% .034 264.665);--tw-prose-bold:oklch(21% .034 264.665);--tw-prose-counters:oklch(55.1% .027 264.364);--tw-prose-bullets:oklch(87.2% .01 258.338);--tw-prose-hr:oklch(92.8% .006 264.531);--tw-prose-quotes:oklch(21% .034 264.665);--tw-prose-quote-borders:oklch(92.8% .006 264.531);--tw-prose-captions:oklch(55.1% .027 264.364);--tw-prose-kbd:oklch(21% .034 264.665);--tw-prose-kbd-shadows:NaN NaN NaN;--tw-prose-code:oklch(21% .034 264.665);--tw-prose-pre-code:oklch(92.8% .006 264.531);--tw-prose-pre-bg:oklch(27.8% .033 256.848);--tw-prose-th-borders:oklch(87.2% .01 258.338);--tw-prose-td-borders:oklch(92.8% .006 264.531);--tw-prose-invert-body:oklch(87.2% .01 258.338);--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:oklch(70.7% .022 261.325);--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:oklch(70.7% .022 261.325);--tw-prose-invert-bullets:oklch(44.6% .03 256.802);--tw-prose-invert-hr:oklch(37.3% .034 259.733);--tw-prose-invert-quotes:oklch(96.7% .003 264.542);--tw-prose-invert-quote-borders:oklch(37.3% .034 259.733);--tw-prose-invert-captions:oklch(70.7% .022 261.325);--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:oklch(87.2% .01 258.338);--tw-prose-invert-pre-bg:#00000080;--tw-prose-invert-th-borders:oklch(44.6% .03 256.802);--tw-prose-invert-td-borders:oklch(37.3% .034 259.733);font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.571429em;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-8{margin-top:calc(var(--spacing)*8)}.flex{display:flex}.grid{display:grid}.hidden{display:none}.table{display:table}.h-\[36px\]{height:36px}.h-full{height:100%}.w-24{width:calc(var(--spacing)*24)}.w-auto{width:auto}.w-full{width:100%}.max-w-none{max-width:none}.flex-1{flex:1}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-start{justify-content:flex-start}.gap-1{gap:calc(var(--spacing)*1)}.gap-2{gap:calc(var(--spacing)*2)}.gap-4{gap:calc(var(--spacing)*4)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-8{padding-block:calc(var(--spacing)*8)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.text-blue{color:var(--color-blue)}.text-gray-500{color:var(--color-gray-500)}.italic{font-style:italic}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,visibility,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (min-width:48rem){.md\:flex{display:flex}.md\:w-28{width:calc(var(--spacing)*28)}.md\:w-\[750px\]{width:750px}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:px-0{padding-inline:calc(var(--spacing)*0)}}.prose-code\:rounded-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:var(--radius-sm)}.prose-code\:bg-gray-200 :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:var(--color-gray-200)}.prose-code\:px-1 :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline:calc(var(--spacing)*1)}.prose-code\:font-mono :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-family:var(--font-mono)}.prose-code\:font-medium :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.prose-code\:before\:content-none :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose-code\:after\:content-none :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:var(--tw-content);--tw-content:none;content:none}}html{scrollbar-gutter:stable}@supports not (scrollbar-gutter:stable){html{overflow-y:scroll}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}
首页 关于 只花不到150元,部署一套可能是最佳体验的家庭网络系统 前言
哪个男孩不想要一个可以自由驰骋互联网的网络呢?
关于家中的互联网建设这一块,已经不知道有多少博主聊过,自己也是来来回回折腾了很多种方案。
最近终于找到了我直到目前为止我认为可能是最完美的方案——PaoPaoDNS+PaoPaoGateWay。然后就在自己家的软路由系统里部署了起来,目前也是稳定用了一个月感觉非常的舒适。
但是我家里面用的是软路由+虚拟机的方案,本身全套机器下载价格要400元左右了,而且机器也是做了一点点硬改,没有改机能力的人恐怕用起来也会比较麻烦。
于是我就在想,能不能用比较便宜的方案,和较低的功耗,用一些市面上常见的设备来实现这一套方案呢?
最终预期的结果
在尽可能保证正常网络不会受到影响的情况下,实现网内透明代理,以用于科学上网。
附赠功能: 去广告,虚拟局域网组网等
设备选择和采购
于是经过我的思考,最后做出了如下的设备方案:
一台硬路由,要可以刷入支持设置静态路由,静态DHCP的系统(OpenWRT、爱快、ROS等)
一台可以部署Docker容器的机器,例如一台小型ARM主机(玩客云,x905电视盒子等)
一台低功耗x86小主机(最好支持AES硬解)
以上设备各位读者可以根据自身的经济条件和现有的设备来决定如何选择,比如全放进虚拟机里之类。而我这次选择的设备是下面这几个。
硬路由-JCG Q30 Pro: 59元
这个价格不算特别的大众,这是一台天线坏掉的机器,而我的家里面因为还有三个其他的无线路由器当做AP使用,所以我不需要无线网络功能。
这台机器的芯片是联发科的mt7981,内存是256m(也有512m的版本),性能较好,可以轻松跑满千兆。而且这款机器还是被OpenWRT和immortalwrt官方支持的型号,可以直接刷主线版的固件,这样也可以避免一些网上所谓的“大神”编译的固件中的各种坑。
机器怎么刷机我这里就不说了,网上有一些现成的资料,在这里说会导致教程太过于复杂,而且也许你的设备也不需要刷机,对吧。
其实我个人目前比较推荐的机器是爱快IK-Q3000,不用刷机就能享受官方的爱快的系统固件,机身自己支持AX3000,如果没有其他无线组网,一台机器就能解决大部分人家中的路由和WiFI了。现在这个机器京东售价159,同样所谓mt7981芯片的机器,他也就比别的机器贵了20-30。30块钱买个免刷机带售后的爱快系统我觉得还是挺香的。(不过不清楚这台机器有没有硬件转发,如果没有的话还是不要用了)
ARM主机-玩客云: 28元
玩客云算是我们垃圾佬应该非常熟悉的一个东西了,他本身是一个拿来做PCDN的所谓的“挖矿”设备,后续随着PCDN的收益越来越低,运营商对PCDN的打击等等原因,现在网上有着大量的机器在流通。而且由于存世量多,玩的人也多,这机器在价格便宜的同时,机器的玩法也开发的比较全面,很多系统都能刷入进去。
我们这里选择给它刷入Armbian,以用来部署Docker容器,刷机方法大家也可以参考网络资料。
X86小主机-中兴CT321G2: 本人购入79元,咸鱼现价50元
这个小机器是之前无意中发现的,机身外壳的做工还不错,虽然是塑料但是很厚实。这个机器由于只有一个千兆网口,不好做软路由,且只有一个无法更换4g硬盘,所以对于垃圾佬来说,可玩性就有点差了,导致价格一直不高。但是这台机器的CPU是小主机里面不太常见的AMD GX-218GL,这块CPU性能和J1900差不太多,功耗也都是在10w左右,但是他有一个J1900没有的优势: 支持AES硬解。
大家都知道AES硬解意味着什么,加上小尺寸,低功耗,所以这台机器非常适合拿来做我们的网关机。
注意: 这个机器只有VGA输出,需要你准备支持VGA的显示器和线,或者转换线。
系统搭建
主网络
首先要保证你的网络是正常的,你需要了解如何使用你的路由器正确的设置上网功能。
我这里以最常见的网络地址作为演示,你可以根据你的需求来设置自己的网段。
路由器IP: 192.168.1.1
DHCP范围: 192.168.1.101-192.168.1.200
局域网段: 192.168.1.0/24
子网掩码: 255.255.255.0
网关机IP: 192.168.1.2
Docker容器机IP: 192.168.1.3
网关机
首先要准备一下PaoPaoGateWay的系统镜像,由于是在物理机运行,所以需要全网卡驱动的支持。官方Github上的镜像是默认不带全网卡驱动的,需要我们用官方的docker来定制一下ios镜像。
定制方式非常简单,随便找一台x86的装有docker的机器(官方容器不支持arm),运行下面两条命令,就能在当前目录获得一个具有全部网卡的ios镜像了。
docker pull sliamb/ppgwiso:fullmod
docker run --rm -v .:/data sliamb/ppgwiso:fullmod
如果你不方便定制,也可以下载我定制好的镜像文件(记得解压)。
paopao-gateway-x86-64-custom-364b136.zip
准备一个写磁盘的工具,Rufus、balenaEtcher、UltraISO之类的都可以,我这里使用Rufus。
准备一个U盘,将镜像文件写入到U盘里。
然后将U盘插入x86小主机,在Bios里设置为从U盘启动系统,通电自动启动系统,最后用网线将网口和路由器的Lan口进行连接。
这样网关机这里就算设置完成了。
注:
如果有条件可以将网关机接上屏幕开机测试一下,看看能不能正常启动开机看到日志。
系统测试稳定之后,可以尝试用PE将ISO镜像写入到系统内置磁盘里,这样就可以不插U盘启动了,不过这样后面更新会稍微麻烦点。
Docker机
首先搭建好Docker环境,这里根据不同的设备和系统会有不同的方法,请根据网络上的教程自行操作。
创建目录DNS,并且在其中创建docker-compose.yaml
文件,用于配置容器。
2024年10月6日更新 ⬇️⬇️⬇️⬇️⬇️
之前发现有一个节点连接的问题。
如果你的节点域名被设置成了国内国外解析的结果不一致,可能会导致你用 PPGW 无法连接到节点。
PPGW官方给出的方案,是开启dns_burn
功能,这样会导致你的节点里创建出来一堆可用的节点。
具体的原因可以参考https://github.com/kkkgo/PaoPaoGateWay/issues/20 。
不过我们这里是有办法解决的。
首先把国内的DNS容器(PaoPaoDNS-China)的53端口,映射到5304端口。然后去掉国外的DNS容器(PaoPaoDNS-Global)的端口映射。就能解决节点无法连接的问题。
原因是 PPGW 的节点解析,会使用 PPDNS 的 5304 端口来解析,而 5304 端口实际上是 PPDNS 的底层使用国外可信加密DNS的转发。但是某些节点的设置会导致国内国外节点域名解析不一致,这样就会导致网关拿到错误的地址,导致无法访问。
而且这里不能直接把 ppgw.ini
的 dns_port
修改到 53
,因为本身 53 端口是转发到了 PaoPaoDNS-Global 的,于是国外IP会返回 FakeIP ,造成循环。
看不懂没关系,用就是了。
2024年10月6日更新 ⬆️⬆️⬆️⬆️⬆️
docker-compose.yaml
文件内容参考如下。
services :
paopaodns_china :
image : sliamb/paopaodns: latest
container_name : PaoPaoDNS- China
restart : always
volumes :
- ./PaoPaoDNS- China: /data
networks :
dns :
ipv4_address : 172.30.1.10
environment :
- TZ=Asia/Shanghai
- UPDATE=weekly
- DNS_SERVERNAME=PaoPaoDNS- China
- DNSPORT=53
- CNAUTO=no
ports :
- "5304:53/udp"
- "5304:53/tcp"
paopaodns _global :
image : sliamb/paopaodns: latest
container_name : PaoPaoDNS- Global
restart : always
volumes :
- ./PaoPaoDNS- Global: /data
networks :
dns :
ipv4_address : 172.30.1.20
environment :
- TZ=Asia/Shanghai
- UPDATE=weekly
- DNS_SERVERNAME=PaoPaoDNS- Global
- DNSPORT=53
- CNAUTO=yes
- CNFALL=yes
- CN_TRACKER=yes
- USE_HOSTS=no
- IPV6=no
- SOCKS5=192.168.1.2: 1080
- SERVER_IP=192.168.1.3
- CUSTOM_FORWARD=192.168.1.2: 53
- AUTO_FORWARD=yes
- AUTO_FORWARD_CHECK=yes
- USE_MARK_DATA=yes
- HTTP_FILE=yes
ports :
- "7889:7889/tcp"
adguard_home :
image : adguard/adguardhome: latest
container_name : AdGuardHome
restart : always
depends_on :
- paopaodns_china
- paopaodns_global
volumes :
- ./AdGuardHome: /opt/adguardhome/work
- ./AdGuardHome: /opt/adguardhome/conf
networks :
dns :
ipv4_address : 172.30.1.2
environment :
- TZ=Asia/Shanghai
ports :
- "53:53/udp"
- "53:53/tcp"
- "80:80/tcp"
- "3000:3000/tcp"
networks :
dns :
driver : bridge
ipam :
driver : default
config :
- subnet : 172.30.1.0/24
gateway : 172.30.1.1
解释一下这个配置文件。
这个配置文件定义了三个容器。
两个PaoPaoDNS,用来作为AdguardHome的上游DNS,其中一个容器没有做特殊的配置,仅当做本地递归DNS服务器使用。而另一台则添加了分流相关的设置,用于对需要出国的设备进行DNS分流处理。
AdguardHome,用于提供本地DNS服务,给不同的客户端配置不同的上游DNS,以及去广告(虽然是他的本职,但是这里反而成了附赠的功能了)。
注: 爱快官方之前在论坛中提到,系统更新到3.7.12后,DHCP设置将支持对不同的客户端配置不同的DNS,所以用爱快系统的可以根据需求不使用AdguardHome。
接下来启动容器。
docker compose up -d
容器正常启动后,则可以使用本机IP:3000
访问AdguardHome的安装页面了,设置一下用户名和密码,以及WebUI的端口(建议80)即可。
网络配置
因为我文章里是使用的OpenWRT作为路由系统,所以这里也是用OpenWRT来演示。
启动网关机和Docker容器机,让他们的信息出现在你的路由器里面。
首先要固定一下IP。
打开 网络→DHCP/DNS→静态地址分配,将网关机的IP固定为192.168.1.2
,将Docker机的IP固定为192.168.1.3
。
然后将DHCP默认的DNS设置为192.168.1.3
(如果需要输入两个地址就都填一样的)。
接下来要设置网内设备的DNS。
打开 网络→接口→lan→DHCP服务器→高级设置,在DHCP选项中添加。
6,192.168.1.3
这个6,
后面的值就是你的Docker机的IP。
然后重启一下网关机和Docker机,让他们可以获取到新的IP和DNS。
接下来网页打开AdguardHome的后台http://192.168.1.3 ,在DNS设置中,将上游DNS设置为172.30.1.10
,并且关闭缓存。
这时我们可以试一下我们的DNS能否正常使用。
nslookup whoami.03k.org 192.168 .1.3
服务器: Unknown
Address: 192.168 .1.3
非权威应答:
名称: whoami.03k.org
Address: 123.234 .123.234
返回的地址如果是你的公网IP网段,就说明递归DNS已经生效了。
接下来是设置静态路由,我们回到OpenWRT的界面。
打开 网络→路由→静态 IPv4 路由,添加一条新的静态路由,类型unicast
,目标11.0.0.0/8
,网关192.168.1.2
。
最后要屏蔽掉对FakeIP的NAT。
打开 网络→防火墙→通信规则,添加一条新的规则,源区域为lan
,目标区域为wan
,目标地址为11.0.0.0/8
,操作为丢弃
。
注:
如果有使用一些纯靠IP访问的软件(例如网飞、Telegram),还需要把他们的IP端也设置相同的静态路由和通信规则中,比较长这里我就不写了,有需求的可以自行添加。
到这里网络路由相关内容设置完毕。
网关配置
网关配置文件在Docker机器的DNS/PaoPaoDNS-Global
目录中的ppgw.ini
。
mode = suburl
fake_cidr = 11.0.0.0/8
dns_ip = 192.168.1.3
dns_port = 5304
clash_web_port = "80 "
clash_web_password = "clashpass "
openport = no
udp_enable = no
sleeptime = 30
socks5_ip = "192.168.1.2 "
socks5_port = "7890 "
ovpnfile = "custom.ovpn "
ovpn_username = ""
ovpn_password = ""
yamlfile = "custom.yaml "
suburl = "https://... "
subtime = 1d
fast_node = yes
test_node_url = "https://www.youtube.com/generate_204 "
ext_node = "Traffic|Expire| GB|Days|Date "
cpudelay = "3000 "
dns_burn = no
ex_dns = "192.168.1.3:53 "
net_rec = no
max_rec = 5000
更详细的参数解释,以及自定义规则等等,请参考官方的文档 ,如果没有特殊需求,按本文的配置即可。
配置设备DNS
我的教程中的方案,是建立在网内只有一部分设备出国,另一部分正常用网的场景,所以需要针对不同的设备,设置不同的上游DNS服务器。
如果你没有这种需求,可以直接在网络配置那一步中,将上游DNS设置为172.30.1.20
,就不用继续往下看了。
如果你也像我一样,只需要部分的设备走出国规则,那就还需要在多一步设置。
打开AdguardHome的后台http://192.168.1.3 。
打开客户端设置,添加客户端。
添加需要出国的设备的IP或者IP段,然后在下面的自定义上游的地方,将上游DNS设置为172.30.1.20
,然后保存即可。
至此系统全部搭建完毕。
测试
可以使用Speedtest,分别选择国内和国外的测速节点,看一下带宽能否跑满。
可以在https://ip111.cn 或者https://ip.skk.moe 检查一下IP分流是否正常。
可以用NatTypeTester检查一下Nat等级。
总结
整套设备花费是59+28+50=137元,这里是没有计算U盘和交换机的价格。
U盘作为一个搞机佬,我相信各位家里一定会有的,而交换机要看自己网内具体有多少需要网线的设备,所以我就没有算在内。
这里面路由器的价格可能会有一些上下波动,比如你需要一款可以跑满千兆的路由器,又不想刷机,所以可能买了我推荐的爱快Q3000,那价格就一下多了100元了,但是你买了更好的路由器就算不玩这套系统,那也可以让网络体验变好,也是不亏。而如果你家的网络没有达到千兆,比如只有500M甚至100M,那你大可买一些mt7621的路由器,刷个OP或者爱快的固件,这种路由器咸鱼50以内可以随便买。
希望这篇文章可以帮助到一直想要一套舒适的网络的你。
# DNS # 宽带 # 网络
评论
| | 构建时间: 2025-09-02 22:08:06