[{"data":1,"prerenderedAt":695},["ShallowReactive",2],{"\u002Fdocs\u002Fserver\u002Freverse-proxy":3},{"id":4,"title":5,"body":6,"description":687,"extension":688,"meta":689,"navigation":690,"path":691,"seo":692,"stem":693,"__hash__":694},"docs\u002Fdocs\u002Fserver\u002Freverse-proxy.md","HTTPS & Reverse Proxy",{"type":7,"value":8,"toc":680},"minimark",[9,13,22,58,61,80,91,96,99,110,113,407,411,426,574,578,584,646,654,658,676],[10,11,5],"h1",{"id":12},"https-reverse-proxy",[14,15,16,17,21],"p",{},"The NetIgnite server speaks plain HTTP. Put it behind a reverse proxy that terminates TLS before\nyou use it outside ",[18,19,20],"code",{},"localhost",":",[23,24,25,48],"ul",{},[26,27,28,32,33,36,37,40,41,43,44,47],"li",{},[29,30,31],"strong",{},"Logins need HTTPS."," Production builds mark the ",[18,34,35],{},"session"," cookie as ",[18,38,39],{},"Secure",". Browsers only\nstore it over HTTPS or on ",[18,42,20],{},", so logging in over ",[18,45,46],{},"http:\u002F\u002F\u003Cserver-ip>:18232"," fails.",[26,49,50,53,54,57],{},[29,51,52],{},"Agent credentials."," Agents send their ID and secret in an HTTP Basic ",[18,55,56],{},"Authorization"," header.\nWithout TLS, anyone on the path can read them.",[14,59,60],{},"The dashboard, the REST API and the agent WebSocket share one port, so a single proxy rule covers\nall of them. The proxy must:",[62,63,64,71,77],"ol",{},[26,65,66,67,70],{},"forward WebSocket upgrades for ",[18,68,69],{},"\u002Fapi\u002Fagent-control-service",",",[26,72,73,74,76],{},"pass the ",[18,75,56],{}," header through (all proxies below do this by default),",[26,78,79],{},"allow idle connections longer than 60 seconds. The server sends each agent a heartbeat once a\nminute, so a 60-second idle timeout can cut agent connections.",[14,81,82,83,86,87,90],{},"The examples assume NetIgnite runs on the same host at ",[18,84,85],{},"127.0.0.1:18232",", published as\n",[18,88,89],{},"netignite.example.com",".",[92,93,95],"h2",{"id":94},"caddy","Caddy",[14,97,98],{},"Caddy obtains certificates automatically and proxies WebSockets without extra configuration.",[100,101,108],"pre",{"className":102,"code":104,"filename":105,"language":106,"meta":107},[103],"language-text","netignite.example.com {\n    reverse_proxy 127.0.0.1:18232\n}\n","Caddyfile","text","",[18,109,104],{"__ignoreMap":107},[92,111,112],{"id":112},"nginx",[100,114,118],{"className":115,"code":116,"filename":117,"language":112,"meta":107,"style":107},"language-nginx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","map $http_upgrade $connection_upgrade {\n    default upgrade;\n    ''      close;\n}\n\nserver {\n    listen 443 ssl;\n    http2 on;\n    server_name netignite.example.com;\n\n    ssl_certificate     \u002Fetc\u002Fletsencrypt\u002Flive\u002Fnetignite.example.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fnetignite.example.com\u002Fprivkey.pem;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:18232;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection $connection_upgrade;\n\n        # Agents may be idle for a minute between heartbeats.\n        proxy_read_timeout 300s;\n        proxy_send_timeout 300s;\n    }\n}\n","netignite.conf",[18,119,120,143,155,167,173,180,189,204,210,220,225,236,247,252,265,276,287,304,319,334,348,363,368,375,386,396,402],{"__ignoreMap":107},[121,122,125,129,133,137,139],"span",{"class":123,"line":124},"line",1,[121,126,128],{"class":127},"spNyl","map",[121,130,132],{"class":131},"sMK4o"," $",[121,134,136],{"class":135},"sHdIc","http_upgrade",[121,138,132],{"class":131},[121,140,142],{"class":141},"sTEyZ","connection_upgrade {\n",[121,144,146,149,152],{"class":123,"line":145},2,[121,147,148],{"class":131},"    default",[121,150,151],{"class":141}," upgrade",[121,153,154],{"class":131},";\n",[121,156,158,162,165],{"class":123,"line":157},3,[121,159,161],{"class":160},"sfazB","    ''",[121,163,164],{"class":141},"      close",[121,166,154],{"class":131},[121,168,170],{"class":123,"line":169},4,[121,171,172],{"class":141},"}\n",[121,174,176],{"class":123,"line":175},5,[121,177,179],{"emptyLinePlaceholder":178},true,"\n",[121,181,183,186],{"class":123,"line":182},6,[121,184,185],{"class":127},"server",[121,187,188],{"class":141}," {\n",[121,190,192,195,199,202],{"class":123,"line":191},7,[121,193,194],{"class":131},"    listen ",[121,196,198],{"class":197},"sbssI","443",[121,200,201],{"class":141}," ssl",[121,203,154],{"class":131},[121,205,207],{"class":123,"line":206},8,[121,208,209],{"class":131},"    http2 on;\n",[121,211,213,216,218],{"class":123,"line":212},9,[121,214,215],{"class":131},"    server_name ",[121,217,89],{"class":141},[121,219,154],{"class":131},[121,221,223],{"class":123,"line":222},10,[121,224,179],{"emptyLinePlaceholder":178},[121,226,228,231,234],{"class":123,"line":227},11,[121,229,230],{"class":131},"    ssl_certificate ",[121,232,233],{"class":141},"    \u002Fetc\u002Fletsencrypt\u002Flive\u002Fnetignite.example.com\u002Ffullchain.pem",[121,235,154],{"class":131},[121,237,239,242,245],{"class":123,"line":238},12,[121,240,241],{"class":131},"    ssl_certificate_key ",[121,243,244],{"class":141},"\u002Fetc\u002Fletsencrypt\u002Flive\u002Fnetignite.example.com\u002Fprivkey.pem",[121,246,154],{"class":131},[121,248,250],{"class":123,"line":249},13,[121,251,179],{"emptyLinePlaceholder":178},[121,253,255,258,262],{"class":123,"line":254},14,[121,256,257],{"class":127},"    location",[121,259,261],{"class":260},"sBMFI"," \u002F ",[121,263,264],{"class":141},"{\n",[121,266,268,271,274],{"class":123,"line":267},15,[121,269,270],{"class":131},"        proxy_pass ",[121,272,273],{"class":141},"http:\u002F\u002F127.0.0.1:18232",[121,275,154],{"class":131},[121,277,279,282,285],{"class":123,"line":278},16,[121,280,281],{"class":131},"        proxy_http_version ",[121,283,284],{"class":197},"1.1",[121,286,154],{"class":131},[121,288,290,293,296,299,302],{"class":123,"line":289},17,[121,291,292],{"class":131},"        proxy_set_header ",[121,294,295],{"class":141},"Host ",[121,297,298],{"class":131},"$",[121,300,301],{"class":141},"host",[121,303,154],{"class":131},[121,305,307,309,312,314,317],{"class":123,"line":306},18,[121,308,292],{"class":131},[121,310,311],{"class":141},"X-Forwarded-For ",[121,313,298],{"class":131},[121,315,316],{"class":141},"proxy_add_x_forwarded_for",[121,318,154],{"class":131},[121,320,322,324,327,329,332],{"class":123,"line":321},19,[121,323,292],{"class":131},[121,325,326],{"class":141},"X-Forwarded-Proto ",[121,328,298],{"class":131},[121,330,331],{"class":141},"scheme",[121,333,154],{"class":131},[121,335,337,339,342,344,346],{"class":123,"line":336},20,[121,338,292],{"class":131},[121,340,341],{"class":141},"Upgrade ",[121,343,298],{"class":131},[121,345,136],{"class":141},[121,347,154],{"class":131},[121,349,351,353,356,358,361],{"class":123,"line":350},21,[121,352,292],{"class":131},[121,354,355],{"class":141},"Connection ",[121,357,298],{"class":131},[121,359,360],{"class":141},"connection_upgrade",[121,362,154],{"class":131},[121,364,366],{"class":123,"line":365},22,[121,367,179],{"emptyLinePlaceholder":178},[121,369,371],{"class":123,"line":370},23,[121,372,374],{"class":373},"sHwdD","        # Agents may be idle for a minute between heartbeats.\n",[121,376,378,381,384],{"class":123,"line":377},24,[121,379,380],{"class":131},"        proxy_read_timeout ",[121,382,383],{"class":197},"300s",[121,385,154],{"class":131},[121,387,389,392,394],{"class":123,"line":388},25,[121,390,391],{"class":131},"        proxy_send_timeout ",[121,393,383],{"class":197},[121,395,154],{"class":131},[121,397,399],{"class":123,"line":398},26,[121,400,401],{"class":141},"    }\n",[121,403,405],{"class":123,"line":404},27,[121,406,172],{"class":141},[92,408,410],{"id":409},"apache","Apache",[14,412,413,414,417,418,421,422,425],{},"Requires Apache 2.4.47 or newer with ",[18,415,416],{},"mod_proxy",", ",[18,419,420],{},"mod_proxy_http"," and ",[18,423,424],{},"mod_ssl"," enabled.",[100,427,430],{"className":428,"code":429,"filename":117,"language":409,"meta":107,"style":107},"language-apache shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003CVirtualHost *:443>\n    ServerName netignite.example.com\n\n    SSLEngine on\n    SSLCertificateFile    \u002Fetc\u002Fletsencrypt\u002Flive\u002Fnetignite.example.com\u002Ffullchain.pem\n    SSLCertificateKeyFile \u002Fetc\u002Fletsencrypt\u002Flive\u002Fnetignite.example.com\u002Fprivkey.pem\n\n    ProxyPreserveHost On\n    ProxyTimeout 300\n    ProxyPass        \u002F http:\u002F\u002F127.0.0.1:18232\u002F upgrade=websocket\n    ProxyPassReverse \u002F http:\u002F\u002F127.0.0.1:18232\u002F\n\u003C\u002FVirtualHost>\n",[18,431,432,446,454,458,466,474,482,486,494,502,535,564],{"__ignoreMap":107},[121,433,434,437,440,443],{"class":123,"line":124},[121,435,436],{"class":131},"\u003C",[121,438,439],{"class":141},"VirtualHost ",[121,441,442],{"class":160},"*:443",[121,444,445],{"class":131},">\n",[121,447,448,451],{"class":123,"line":145},[121,449,450],{"class":131},"    ServerName",[121,452,453],{"class":141}," netignite.example.com\n",[121,455,456],{"class":123,"line":157},[121,457,179],{"emptyLinePlaceholder":178},[121,459,460,463],{"class":123,"line":169},[121,461,462],{"class":131},"    SSLEngine",[121,464,465],{"class":141}," on\n",[121,467,468,471],{"class":123,"line":175},[121,469,470],{"class":131},"    SSLCertificateFile",[121,472,473],{"class":141},"    \u002Fetc\u002Fletsencrypt\u002Flive\u002Fnetignite.example.com\u002Ffullchain.pem\n",[121,475,476,479],{"class":123,"line":182},[121,477,478],{"class":131},"    SSLCertificateKeyFile",[121,480,481],{"class":141}," \u002Fetc\u002Fletsencrypt\u002Flive\u002Fnetignite.example.com\u002Fprivkey.pem\n",[121,483,484],{"class":123,"line":191},[121,485,179],{"emptyLinePlaceholder":178},[121,487,488,491],{"class":123,"line":206},[121,489,490],{"class":131},"    ProxyPreserveHost",[121,492,493],{"class":141}," On\n",[121,495,496,499],{"class":123,"line":212},[121,497,498],{"class":131},"    ProxyTimeout",[121,500,501],{"class":197}," 300\n",[121,503,504,507,510,513,515,518,520,522,524,527,529,532],{"class":123,"line":222},[121,505,506],{"class":131},"    ProxyPass",[121,508,509],{"class":141},"        \u002F http:\u002F\u002F",[121,511,512],{"class":197},"127",[121,514,90],{"class":141},[121,516,517],{"class":197},"0",[121,519,90],{"class":141},[121,521,517],{"class":197},[121,523,90],{"class":141},[121,525,526],{"class":197},"1",[121,528,21],{"class":141},[121,530,531],{"class":197},"18232",[121,533,534],{"class":141},"\u002F upgrade=websocket\n",[121,536,537,540,543,545,547,549,551,553,555,557,559,561],{"class":123,"line":227},[121,538,539],{"class":131},"    ProxyPassReverse",[121,541,542],{"class":141}," \u002F http:\u002F\u002F",[121,544,512],{"class":197},[121,546,90],{"class":141},[121,548,517],{"class":197},[121,550,90],{"class":141},[121,552,517],{"class":197},[121,554,90],{"class":141},[121,556,526],{"class":197},[121,558,21],{"class":141},[121,560,531],{"class":197},[121,562,563],{"class":141},"\u002F\n",[121,565,566,569,572],{"class":123,"line":238},[121,567,568],{"class":131},"\u003C\u002F",[121,570,571],{"class":141},"VirtualHost",[121,573,445],{"class":131},[92,575,577],{"id":576},"agent-settings-behind-a-proxy","Agent settings behind a proxy",[14,579,580,581,583],{},"Point your agents at the public hostname on port ",[18,582,198],{}," with TLS enabled. For the ESP32 agent:",[100,585,590],{"className":586,"code":587,"filename":588,"language":589,"meta":107,"style":107},"language-cpp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","#define C_CONTROL_SERVER_HOST \"netignite.example.com\"\n#define C_CONTROL_SERVER_PORT (uint16_t) 443\n#define C_CONTROL_SERVER_USE_SSL (bool) true\n","config.h","cpp",[18,591,592,610,629],{"__ignoreMap":107},[121,593,594,598,602,605,607],{"class":123,"line":124},[121,595,597],{"class":596},"s7zQu","#define",[121,599,601],{"class":600},"s2Zo4"," C_CONTROL_SERVER_HOST",[121,603,604],{"class":131}," \"",[121,606,89],{"class":160},[121,608,609],{"class":131},"\"\n",[121,611,612,614,617,620,623,626],{"class":123,"line":145},[121,613,597],{"class":596},[121,615,616],{"class":600}," C_CONTROL_SERVER_PORT",[121,618,619],{"class":131}," (",[121,621,622],{"class":135},"uint16_t",[121,624,625],{"class":131},")",[121,627,628],{"class":197}," 443\n",[121,630,631,633,636,638,641,643],{"class":123,"line":157},[121,632,597],{"class":596},[121,634,635],{"class":600}," C_CONTROL_SERVER_USE_SSL",[121,637,619],{"class":131},[121,639,640],{"class":135},"bool",[121,642,625],{"class":131},[121,644,645],{"class":131}," true\n",[14,647,648,649,90],{},"The ESP32 agent verifies the server certificate against a bundle of public root CAs (including\nLet's Encrypt). Self-signed certificates or a private CA only work if you\n",[650,651,653],"a",{"href":652},"\u002Fdocs\u002Fagents\u002Fesp32#certificate-bundle","add your CA to the bundle",[92,655,657],{"id":656},"checking-the-setup","Checking the setup",[62,659,660,667,673],{},[26,661,662,663,666],{},"Open ",[18,664,665],{},"https:\u002F\u002Fnetignite.example.com"," and log in.",[26,668,669,670,90],{},"Start an agent and watch the server log for ",[18,671,672],{},"Agent '\u003Cid>' connected",[26,674,675],{},"If the agent connects and drops again after about a minute, raise the proxy's idle timeout.",[677,678,679],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}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 .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":107,"searchDepth":145,"depth":145,"links":681},[682,683,684,685,686],{"id":94,"depth":145,"text":95},{"id":112,"depth":145,"text":112},{"id":409,"depth":145,"text":410},{"id":576,"depth":145,"text":577},{"id":656,"depth":145,"text":657},"Serve the NetIgnite dashboard and the agent WebSocket over HTTPS with Caddy, nginx or Apache.","md",{},{"title":5},"\u002Fdocs\u002Fserver\u002Freverse-proxy",{"title":5,"description":687},"docs\u002Fserver\u002Freverse-proxy","bxuI7Zl7vWJhYSkCt7XgveaxKeGgKMAdPFcgTf4JIp4",1792355946317]