[{"data":1,"prerenderedAt":786},["ShallowReactive",2],{"navigation_docs_en":3,"-en-self-hosting-operations-and-security-security-and-networking":143,"-en-self-hosting-operations-and-security-security-and-networking-surround":781},[4,103,124],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":36},"Self-hosting","i-lucide-server","\u002Fen\u002Fself-hosting","en\u002F1.self-hosting",[10,37,57,77],{"title":11,"icon":12,"path":13,"stem":14,"children":15,"page":36},"Getting started","i-lucide-rocket","\u002Fen\u002Fself-hosting\u002Fgetting-started","en\u002F1.self-hosting\u002F1.getting-started",[16,21,26,31],{"title":17,"path":18,"stem":19,"icon":20},"Quick start (guided)","\u002Fen\u002Fself-hosting\u002Fgetting-started\u002Fquick-start","en\u002F1.self-hosting\u002F1.getting-started\u002F1.quick-start","i-lucide-wand-2",{"title":22,"path":23,"stem":24,"icon":25},"Overview","\u002Fen\u002Fself-hosting\u002Fgetting-started\u002Foverview","en\u002F1.self-hosting\u002F1.getting-started\u002F2.overview","i-lucide-layout-dashboard",{"title":27,"path":28,"stem":29,"icon":30},"Requirements","\u002Fen\u002Fself-hosting\u002Fgetting-started\u002Frequirements","en\u002F1.self-hosting\u002F1.getting-started\u002F3.requirements","i-lucide-cpu",{"title":32,"path":33,"stem":34,"icon":35},"Manual install","\u002Fen\u002Fself-hosting\u002Fgetting-started\u002Fmanual-install","en\u002F1.self-hosting\u002F1.getting-started\u002F4.manual-install","i-lucide-terminal",false,{"title":38,"icon":39,"path":40,"stem":41,"children":42,"page":36},"Performance & models","i-lucide-gauge","\u002Fen\u002Fself-hosting\u002Fperformance-and-models","en\u002F1.self-hosting\u002F2.performance-and-models",[43,48,52],{"title":44,"path":45,"stem":46,"icon":47},"GPU acceleration","\u002Fen\u002Fself-hosting\u002Fperformance-and-models\u002Fgpu-acceleration","en\u002F1.self-hosting\u002F2.performance-and-models\u002F1.gpu-acceleration","i-lucide-zap",{"title":49,"path":50,"stem":51,"icon":39},"Performance and memory","\u002Fen\u002Fself-hosting\u002Fperformance-and-models\u002Fperformance-and-memory","en\u002F1.self-hosting\u002F2.performance-and-models\u002F2.performance-and-memory",{"title":53,"path":54,"stem":55,"icon":56},"Models","\u002Fen\u002Fself-hosting\u002Fperformance-and-models\u002Fmodels","en\u002F1.self-hosting\u002F2.performance-and-models\u002F3.models","i-lucide-brain",{"title":58,"icon":59,"path":60,"stem":61,"children":62,"page":36},"Configuration & access","i-lucide-sliders-horizontal","\u002Fen\u002Fself-hosting\u002Fconfiguration-and-access","en\u002F1.self-hosting\u002F3.configuration-and-access",[63,67,72],{"title":64,"path":65,"stem":66,"icon":59},"Configuration reference","\u002Fen\u002Fself-hosting\u002Fconfiguration-and-access\u002Fconfiguration-reference","en\u002F1.self-hosting\u002F3.configuration-and-access\u002F1.configuration-reference",{"title":68,"path":69,"stem":70,"icon":71},"Licensing and activation","\u002Fen\u002Fself-hosting\u002Fconfiguration-and-access\u002Flicensing","en\u002F1.self-hosting\u002F3.configuration-and-access\u002F2.licensing","i-lucide-key-round",{"title":73,"path":74,"stem":75,"icon":76},"Managing users","\u002Fen\u002Fself-hosting\u002Fconfiguration-and-access\u002Fmanaging-users","en\u002F1.self-hosting\u002F3.configuration-and-access\u002F3.managing-users","i-lucide-users",{"title":78,"icon":79,"path":80,"stem":81,"children":82,"page":36},"Operations & security","i-lucide-shield-check","\u002Fen\u002Fself-hosting\u002Foperations-and-security","en\u002F1.self-hosting\u002F4.operations-and-security",[83,88,93,98],{"title":84,"path":85,"stem":86,"icon":87},"Backups and restore","\u002Fen\u002Fself-hosting\u002Foperations-and-security\u002Fbackups","en\u002F1.self-hosting\u002F4.operations-and-security\u002F1.backups","i-lucide-database-backup",{"title":89,"path":90,"stem":91,"icon":92},"Updating","\u002Fen\u002Fself-hosting\u002Foperations-and-security\u002Fupdating","en\u002F1.self-hosting\u002F4.operations-and-security\u002F2.updating","i-lucide-refresh-cw",{"title":94,"path":95,"stem":96,"icon":97},"Security and networking","\u002Fen\u002Fself-hosting\u002Foperations-and-security\u002Fsecurity-and-networking","en\u002F1.self-hosting\u002F4.operations-and-security\u002F3.security-and-networking","i-lucide-shield",{"title":99,"path":100,"stem":101,"icon":102},"Troubleshooting","\u002Fen\u002Fself-hosting\u002Foperations-and-security\u002Ftroubleshooting","en\u002F1.self-hosting\u002F4.operations-and-security\u002F4.troubleshooting","i-lucide-life-buoy",{"title":104,"icon":105,"path":106,"stem":107,"children":108,"page":36},"App & reference","i-lucide-book-open-text","\u002Fen\u002Freference","en\u002F2.reference",[109,114,119],{"title":110,"path":111,"stem":112,"icon":113},"Install the app","\u002Fen\u002Freference\u002Finstall-the-app","en\u002F2.reference\u002F1.install-the-app","i-lucide-download",{"title":115,"path":116,"stem":117,"icon":118},"How it works","\u002Fen\u002Freference\u002Fhow-it-works","en\u002F2.reference\u002F2.how-it-works","i-lucide-workflow",{"title":120,"path":121,"stem":122,"icon":123},"Data and privacy","\u002Fen\u002Freference\u002Fdata-and-privacy","en\u002F2.reference\u002F3.data-and-privacy","i-lucide-lock",{"title":125,"icon":126,"path":127,"stem":128,"children":129,"page":36},"Chronicler Cloud","i-lucide-cloud","\u002Fen\u002Fcloud","en\u002F3.cloud",[130,134,138],{"title":131,"path":132,"stem":133,"icon":126},"Cloud overview","\u002Fen\u002Fcloud\u002Foverview","en\u002F3.cloud\u002F1.overview",{"title":135,"path":136,"stem":137,"icon":12},"Quick start","\u002Fen\u002Fcloud\u002Fquick-start","en\u002F3.cloud\u002F2.quick-start",{"title":139,"path":140,"stem":141,"icon":142},"Your first chat","\u002Fen\u002Fcloud\u002Fyour-first-chat","en\u002F3.cloud\u002F3.your-first-chat","i-lucide-messages-square",{"id":144,"title":94,"body":145,"description":772,"extension":773,"links":774,"meta":775,"navigation":776,"path":95,"seo":777,"stem":96,"__hash__":780},"docs_en\u002Fen\u002F1.self-hosting\u002F4.operations-and-security\u002F3.security-and-networking.md",{"type":146,"value":147,"toc":762},"minimark",[148,153,219,229,268,272,284,291,295,301,363,374,378,382,385,555,566,569,591,597,601,605,662,668,672,692,696,702,706,758],[149,150,152],"h2",{"id":151},"whats-exposed","What's exposed",[154,155,156,172],"table",{},[157,158,159],"thead",{},[160,161,162,166,169],"tr",{},[163,164,165],"th",{},"Port",[163,167,168],{},"Service",[163,170,171],{},"Who should reach it",[173,174,175,190,203],"tbody",{},[160,176,177,184,187],{},[178,179,180],"td",{},[181,182,183],"code",{},"8410",[178,185,186],{},"Backend API",[178,188,189],{},"Every machine running Chronicler",[160,191,192,197,200],{},[178,193,194],{},[181,195,196],{},"11434",[178,198,199],{},"Model runtime",[178,201,202],{},"Nothing outside the server",[160,204,205,210,213],{},[178,206,207],{},[181,208,209],{},"5432",[178,211,212],{},"Database",[178,214,215,216],{},"Nothing - bound to ",[181,217,218],{},"127.0.0.1",[220,221,222,223,225,226,228],"p",{},"Only ",[181,224,183],{}," needs to be reachable. If the compose file you're using publishes\n",[181,227,196],{}," more widely than you'd like, restrict it the same way Postgres is:",[230,231,237],"pre",{"className":232,"code":233,"filename":234,"language":235,"meta":236,"style":236},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","    ports:\n      - \"127.0.0.1:11434:11434\"\n","docker-compose.yml","yaml","",[181,238,239,252],{"__ignoreMap":236},[240,241,244,248],"span",{"class":242,"line":243},"line",1,[240,245,247],{"class":246},"swJcz","    ports",[240,249,251],{"class":250},"sMK4o",":\n",[240,253,255,258,261,265],{"class":242,"line":254},2,[240,256,257],{"class":250},"      -",[240,259,260],{"class":250}," \"",[240,262,264],{"class":263},"sfazB","127.0.0.1:11434:11434",[240,266,267],{"class":250},"\"\n",[149,269,271],{"id":270},"claim-the-server-immediately","Claim the server immediately",[220,273,274,275,279,280,283],{},"A server with no users offers ",[276,277,278],"strong",{},"Register your admin account"," to whoever reaches\nit first. Between ",[181,281,282],{},"docker compose up -d"," and creating that account, anyone who\ncan reach port 8410 can take it.",[220,285,286,287,290],{},"So: start the stack and register the admin ",[276,288,289],{},"in the same sitting",", from a\nmachine you trust, before opening the port to a wider network.",[149,292,294],{"id":293},"on-a-local-network","On a local network",[220,296,297,298,300],{},"For a server and its users on the same trusted LAN, plain HTTP on ",[181,299,183],{}," is\nusually accepted - the traffic never leaves the building. Restrict it to the\nsubnet at the firewall:",[302,303,304,321],"tabs",{},[305,306,309],"tabs-item",{"icon":307,"label":308},"i-lucide-monitor","Windows (PowerShell as administrator)",[230,310,315],{"className":311,"code":312,"filename":313,"language":314,"meta":236,"style":236},"language-powershell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","New-NetFirewallRule -DisplayName \"Chronicler LAN\" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8410 -RemoteAddress 192.168.1.0\u002F24\n","PowerShell","powershell",[181,316,317],{"__ignoreMap":236},[240,318,319],{"class":242,"line":243},[240,320,312],{},[305,322,324],{"icon":35,"label":323},"Linux (ufw)",[230,325,330],{"className":326,"code":327,"filename":328,"language":329,"meta":236,"style":236},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","sudo ufw allow from 192.168.1.0\u002F24 to any port 8410\n","Linux shell","bash",[181,331,332],{"__ignoreMap":236},[240,333,334,338,341,344,347,350,353,356,359],{"class":242,"line":243},[240,335,337],{"class":336},"sBMFI","sudo",[240,339,340],{"class":263}," ufw",[240,342,343],{"class":263}," allow",[240,345,346],{"class":263}," from",[240,348,349],{"class":263}," 192.168.1.0\u002F24",[240,351,352],{"class":263}," to",[240,354,355],{"class":263}," any",[240,357,358],{"class":263}," port",[240,360,362],{"class":361},"sbssI"," 8410\n",[220,364,365,366,369,370,373],{},"Colleagues then point ",[276,367,368],{},"Settings → Connection → Local"," at\n",[181,371,372],{},"http:\u002F\u002F192.168.1.50:8410",".",[149,375,377],{"id":376},"over-the-internet-use-https","Over the internet: use HTTPS",[379,380,381],"caution",{},"Do not publish port 8410 to the internet directly. Sign-ins and document content\nwould cross the network in clear text.",[220,383,384],{},"Put a reverse proxy in front. Chronicler ships no proxy and no certificates -\nthat stays your choice.",[386,387,388,500],"code-group",{},[230,389,393],{"className":390,"code":391,"filename":392,"language":392,"meta":236,"style":236},"language-nginx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","server {\n    listen 443 ssl;\n    server_name chronicler.example.com;\n\n    ssl_certificate     \u002Fetc\u002Fletsencrypt\u002Flive\u002Fchronicler.example.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fchronicler.example.com\u002Fprivkey.pem;\n\n    client_max_body_size 512M;   # uploads\n\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:8410;\n        proxy_set_header Host              $host;\n        proxy_set_header X-Real-IP         $remote_addr;\n        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_read_timeout 600s;     # answers can take minutes on CPU\n    }\n}\n","nginx",[181,394,395,400,405,411,418,424,430,435,441,446,452,458,464,470,476,482,488,494],{"__ignoreMap":236},[240,396,397],{"class":242,"line":243},[240,398,399],{},"server {\n",[240,401,402],{"class":242,"line":254},[240,403,404],{},"    listen 443 ssl;\n",[240,406,408],{"class":242,"line":407},3,[240,409,410],{},"    server_name chronicler.example.com;\n",[240,412,414],{"class":242,"line":413},4,[240,415,417],{"emptyLinePlaceholder":416},true,"\n",[240,419,421],{"class":242,"line":420},5,[240,422,423],{},"    ssl_certificate     \u002Fetc\u002Fletsencrypt\u002Flive\u002Fchronicler.example.com\u002Ffullchain.pem;\n",[240,425,427],{"class":242,"line":426},6,[240,428,429],{},"    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fchronicler.example.com\u002Fprivkey.pem;\n",[240,431,433],{"class":242,"line":432},7,[240,434,417],{"emptyLinePlaceholder":416},[240,436,438],{"class":242,"line":437},8,[240,439,440],{},"    client_max_body_size 512M;   # uploads\n",[240,442,444],{"class":242,"line":443},9,[240,445,417],{"emptyLinePlaceholder":416},[240,447,449],{"class":242,"line":448},10,[240,450,451],{},"    location \u002F {\n",[240,453,455],{"class":242,"line":454},11,[240,456,457],{},"        proxy_pass http:\u002F\u002F127.0.0.1:8410;\n",[240,459,461],{"class":242,"line":460},12,[240,462,463],{},"        proxy_set_header Host              $host;\n",[240,465,467],{"class":242,"line":466},13,[240,468,469],{},"        proxy_set_header X-Real-IP         $remote_addr;\n",[240,471,473],{"class":242,"line":472},14,[240,474,475],{},"        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;\n",[240,477,479],{"class":242,"line":478},15,[240,480,481],{},"        proxy_set_header X-Forwarded-Proto $scheme;\n",[240,483,485],{"class":242,"line":484},16,[240,486,487],{},"        proxy_read_timeout 600s;     # answers can take minutes on CPU\n",[240,489,491],{"class":242,"line":490},17,[240,492,493],{},"    }\n",[240,495,497],{"class":242,"line":496},18,[240,498,499],{},"}\n",[230,501,506],{"className":502,"code":503,"filename":504,"language":505,"meta":236,"style":236},"language-caddy shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","chronicler.example.com {\n    reverse_proxy 127.0.0.1:8410 {\n        transport http {\n            read_timeout 600s\n        }\n    }\n    request_body {\n        max_size 512MB\n    }\n}\n","Caddyfile","caddy",[181,507,508,513,518,523,528,533,537,542,547,551],{"__ignoreMap":236},[240,509,510],{"class":242,"line":243},[240,511,512],{},"chronicler.example.com {\n",[240,514,515],{"class":242,"line":254},[240,516,517],{},"    reverse_proxy 127.0.0.1:8410 {\n",[240,519,520],{"class":242,"line":407},[240,521,522],{},"        transport http {\n",[240,524,525],{"class":242,"line":413},[240,526,527],{},"            read_timeout 600s\n",[240,529,530],{"class":242,"line":420},[240,531,532],{},"        }\n",[240,534,535],{"class":242,"line":426},[240,536,493],{},[240,538,539],{"class":242,"line":432},[240,540,541],{},"    request_body {\n",[240,543,544],{"class":242,"line":437},[240,545,546],{},"        max_size 512MB\n",[240,548,549],{"class":242,"line":443},[240,550,493],{},[240,552,553],{"class":242,"line":448},[240,554,499],{},[220,556,557,558,561,562,565],{},"Two settings matter and are easy to miss: a ",[276,559,560],{},"generous body size"," (documents are\nlarge) and a ",[276,563,564],{},"long read timeout"," (a CPU-generated answer can take minutes; the\nusual 60-second default will cut it off).",[220,567,568],{},"Then bind the backend to loopback only, so the proxy is the only way in:",[230,570,572],{"className":232,"code":571,"filename":234,"language":235,"meta":236,"style":236},"    ports:\n      - \"127.0.0.1:8410:8410\"\n",[181,573,574,580],{"__ignoreMap":236},[240,575,576,578],{"class":242,"line":243},[240,577,247],{"class":246},[240,579,251],{"class":250},[240,581,582,584,586,589],{"class":242,"line":254},[240,583,257],{"class":250},[240,585,260],{"class":250},[240,587,588],{"class":263},"127.0.0.1:8410:8410",[240,590,267],{"class":250},[220,592,593,594,373],{},"Users enter ",[181,595,596],{},"https:\u002F\u002Fchronicler.example.com",[598,599,600],"tip",{},"A VPN is often the better answer. If everyone already connects to the office\nnetwork remotely, keep Chronicler on the LAN and publish nothing.",[149,602,604],{"id":603},"secrets-to-protect","Secrets to protect",[154,606,607,620],{},[157,608,609],{},[160,610,611,614,617],{},[163,612,613],{},"What",[163,615,616],{},"Where",[163,618,619],{},"Why it matters",[173,621,622,637,651],{},[160,623,624,629,634],{},[178,625,626],{},[181,627,628],{},"POSTGRES_PASSWORD",[178,630,631],{},[181,632,633],{},".env",[178,635,636],{},"The only key to your database volume. Lose it and the data is unreadable; leak it and anyone who can reach the database has everything.",[160,638,639,642,648],{},[178,640,641],{},"Backup archives",[178,643,644,647],{},[181,645,646],{},"backend_uploads",", plus your offsite folder",[178,649,650],{},"A full copy of the database. Protect them like the database itself.",[160,652,653,656,659],{},[178,654,655],{},"Licence key",[178,657,658],{},"Admin console",[178,660,661],{},"Bound to one install, but still yours.",[220,663,664,665,667],{},"The server's signing key is generated on first start and kept in the\n",[181,666,646],{}," volume. You never handle it; just don't delete that volume.",[149,669,671],{"id":670},"accounts","Accounts",[673,674,675,683,686,689],"ul",{},[676,677,678,679,682],"li",{},"Nobody can sign themselves up. Administrators create accounts\n(",[680,681,73],"a",{"href":74},").",[676,684,685],{},"New accounts get a one-time password, shown once, and must set their own on\nfirst sign-in.",[676,687,688],{},"Suspend accounts when people leave - suspension keeps their documents, deletion\ndoesn't.",[676,690,691],{},"Keep the number of administrators small. Administrators can restore backups,\nwhich means reading everything.",[149,693,695],{"id":694},"keeping-it-patched","Keeping it patched",[220,697,698,699,701],{},"Update monthly (",[680,700,89],{"href":90},"), keep Docker itself\nupdated, and patch the host OS. The stack is small - four containers, no plugins,\nno extensions - which is the point.",[149,703,705],{"id":704},"a-short-checklist","A short checklist",[673,707,710,719,725,731,740,746,752],{"className":708},[709],"contains-task-list",[676,711,714,718],{"className":712},[713],"task-list-item",[715,716],"input",{"disabled":416,"type":717},"checkbox"," Admin account registered immediately after first start",[676,720,722,724],{"className":721},[713],[715,723],{"disabled":416,"type":717}," Port 8410 restricted to the network that needs it",[676,726,728,730],{"className":727},[713],[715,729],{"disabled":416,"type":717}," HTTPS in front if it's reachable from outside the LAN",[676,732,734,736,737,739],{"className":733},[713],[715,735],{"disabled":416,"type":717}," ",[181,738,633],{}," backed up somewhere safe, separate from the server",[676,741,743,745],{"className":742},[713],[715,744],{"disabled":416,"type":717}," Scheduled backups on, with an offsite copy",[676,747,749,751],{"className":748},[713],[715,750],{"disabled":416,"type":717}," One restore rehearsed at least once",[676,753,755,757],{"className":754},[713],[715,756],{"disabled":416,"type":717}," Administrator accounts kept to a minimum",[759,760,761],"style",{},"html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":236,"searchDepth":254,"depth":254,"links":763},[764,765,766,767,768,769,770,771],{"id":151,"depth":254,"text":152},{"id":270,"depth":254,"text":271},{"id":293,"depth":254,"text":294},{"id":376,"depth":254,"text":377},{"id":603,"depth":254,"text":604},{"id":670,"depth":254,"text":671},{"id":694,"depth":254,"text":695},{"id":704,"depth":254,"text":705},"Let colleagues in without letting everyone in.","md",null,{},{"icon":97},{"title":778,"description":779},"Chronicler self-hosting security and networking","Expose the Chronicler backend safely, add HTTPS, and protect the database and backups.","pp34cQTGC7TDufGgRJ11VGe4FWTrtxZ5mR3NsdBXF34",[782,784],{"title":89,"path":90,"stem":91,"description":783,"icon":92,"children":-1},"The app and the server update separately. Here's how each one works.",{"title":99,"path":100,"stem":101,"description":785,"icon":102,"children":-1},"The failures people actually hit, and what fixes each one.",1785127057328]