[{"data":1,"prerenderedAt":792},["ShallowReactive",2],{"\u002Fdocs\u002Fserver\u002Fupgrading":3},{"id":4,"title":5,"body":6,"description":784,"extension":785,"meta":786,"navigation":787,"path":788,"seo":789,"stem":790,"__hash__":791},"docs\u002Fdocs\u002Fserver\u002Fupgrading.md","Upgrading from v1",{"type":7,"value":8,"toc":773},"minimark",[9,13,17,55,191,196,283,293,746,750,759,769],[10,11,5],"h1",{"id":12},"upgrading-from-v1",[14,15,16],"p",{},"NetIgnite v2 is a rewrite of the server and the agents. Your v1 data is imported once into the new\ndatabase; the v1 database stays untouched. Agents have to be set up again: v1 agents can't connect\nto a v2 server, and ESP32 boards need the v2 firmware.",[18,19,20],"warning",{},[14,21,22,31,32,35,36,39,40,44,45,50,51,54],{},[23,24,25,26,30],"strong",{},"Using the ",[27,28,29],"code",{},"latest"," image?"," Since 2.0.0, ",[27,33,34],{},"ghcr.io\u002Fnetignite-project\u002Fserver:latest"," is v2. A v1\nserver that pulls it, by hand or with an auto-updater such as Watchtower, starts v2 with an empty\ndatabase next to the v1 one: users, agents and devices seem to be gone, but they're still in\n",[27,37,38],{},"data\u002Fdb.sqlite",", and the server log says ",[41,42,43],"em",{},"Found a NetIgnite v1 database … that hasn't been\nimported",". Continue at ",[46,47,49],"a",{"href":48},"#try-the-import","Try the import",". To stay on v1 for now, use the image\n",[27,52,53],{},"ghcr.io\u002Fnetignite-project\u002Fserver:0.1.3",".",[56,57,58,77],"table",{},[59,60,61],"thead",{},[62,63,64,67,74],"tr",{},[65,66],"th",{},[65,68,69,70,73],{},"v1 (",[27,71,72],{},"0.1.x",")",[65,75,76],{},"v2",[78,79,80,99,116,136,153,167],"tbody",{},[62,81,82,86,90],{},[83,84,85],"td",{},"Database",[83,87,88],{},[27,89,38],{},[83,91,92,95,96,73],{},[27,93,94],{},"data\u002Fnetignite.sqlite"," (the import reads ",[27,97,98],{},"db.sqlite",[62,100,101,104,110],{},[83,102,103],{},"First admin",[83,105,106,107],{},"Password in ",[27,108,109],{},"data\u002Finitial_admin_credentials",[83,111,112,113],{},"Password link in ",[27,114,115],{},"config\u002Finitial_admin_password_reset_token.txt",[62,117,118,121,126],{},[83,119,120],{},"Settings",[83,122,123],{},[27,124,125],{},"config\u002Fconfig.json",[83,127,128,131,132,135],{},[27,129,130],{},"NETIGNITE_*"," environment variables (",[27,133,134],{},"NETIGNITE_APP_URL"," is required)",[62,137,138,141,147],{},[83,139,140],{},"Agent connection",[83,142,143,146],{},[27,144,145],{},"\u002Fapi\u002Fagent-control-service",", ID and secret from the dashboard",[83,148,149,152],{},[27,150,151],{},"\u002Fws\u002Fagent",", credential generated by the agent at enrollment",[62,154,155,158,164],{},[83,156,157],{},"ESP32 setup",[83,159,160,163],{},[27,161,162],{},"config.h",", built with PlatformIO",[83,165,166],{},"Web installer in the dashboard, settings in flash",[62,168,169,172,188],{},[83,170,171],{},"Port, image, volumes",[83,173,174,177,178,177,181,184,185],{},[27,175,176],{},"18232",", ",[27,179,180],{},"ghcr.io\u002Fnetignite-project\u002Fserver",[27,182,183],{},"\u002Fopt\u002Fnetignite\u002Fdata"," and ",[27,186,187],{},"\u002Fopt\u002Fnetignite\u002Fconfig",[83,189,190],{},"unchanged",[192,193,195],"h2",{"id":194},"what-is-migrated","What is migrated",[56,197,198,208],{},[59,199,200],{},[62,201,202,205],{},[65,203,204],{},"v1",[65,206,207],{},"In v2",[78,209,210,222,239,263,275],{},[62,211,212,215],{},[83,213,214],{},"Users",[83,216,217,218,221],{},"Imported with their username, password and role. They get a placeholder email address ",[27,219,220],{},"\u003Cusername>@imported.netignite.invalid",". Passwords are converted to the new hash format at the first login.",[62,223,224,230],{},[83,225,226,227],{},"The v1 ",[27,228,229],{},"admin",[83,231,232,233,235,236,238],{},"Merged into the v2 ",[27,234,229],{},". If nobody has set the v2 ",[27,237,229],{}," password yet (the password link is unused), it takes over the v1 password and the link stops working.",[62,240,241,244],{},[83,242,243],{},"Agents",[83,245,246,247,250,251,254,255,258,259,262],{},"Imported with name and description, but ",[23,248,249],{},"not set up"," (status ",[41,252,253],{},"Not set up","): v1 secrets can't be used in v2. ",[41,256,257],{},"Microcontroller"," agents become ESP32 agents, ",[41,260,261],{},"Server"," agents become Linux agents.",[62,264,265,268],{},[83,266,267],{},"Devices",[83,269,270,271,274],{},"Imported with name, type, description, MAC address, Wake-on-LAN port and agent. Their status check is ",[23,272,273],{},"MAC (IPv6 link-local)",", the check v1 used. Devices without an agent get no status check.",[62,276,277,280],{},[83,278,279],{},"Favorites",[83,281,282],{},"Imported.",[14,284,285,286,288,289,292],{},"Not migrated: v1 agent secrets, v1 logins (users log in again), ",[27,287,125],{}," (set\n",[27,290,291],{},"NETIGNITE_LOG_LEVEL"," instead) and the v1 admin password file. Devices with an invalid MAC address\nare skipped and listed in the import's output.",[294,295,297,301,304,348,352,358,483,509,521,537,540,543,579,588,602,606,632,643,649,653,662,666,675,718,721,725],"steps",{"level":296},"2",[192,298,300],{"id":299},"back-up","Back up",[14,302,303],{},"Stop the v1 server and copy its data and config:",[305,306,312],"pre",{"className":307,"code":308,"filename":309,"language":310,"meta":311,"style":311},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","docker compose down\nsudo cp -a \u002Fopt\u002Fnetignite \u002Fopt\u002Fnetignite-v1-backup\n","Terminal","bash","",[27,313,314,330],{"__ignoreMap":311},[315,316,319,323,327],"span",{"class":317,"line":318},"line",1,[315,320,322],{"class":321},"sBMFI","docker",[315,324,326],{"class":325},"sfazB"," compose",[315,328,329],{"class":325}," down\n",[315,331,333,336,339,342,345],{"class":317,"line":332},2,[315,334,335],{"class":321},"sudo",[315,337,338],{"class":325}," cp",[315,340,341],{"class":325}," -a",[315,343,344],{"class":325}," \u002Fopt\u002Fnetignite",[315,346,347],{"class":325}," \u002Fopt\u002Fnetignite-v1-backup\n",[192,349,351],{"id":350},"start-v2-next-to-the-v1-data","Start v2 next to the v1 data",[14,353,354,355,357],{},"Change the image to v2 and add ",[27,356,134],{}," with the address users open the dashboard at.\nKeep the volumes:",[305,359,364],{"className":360,"code":361,"filename":362,"language":363,"meta":311,"style":311},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","services:\n  netignite-server:\n    image: ghcr.io\u002Fnetignite-project\u002Fserver:latest\n    container_name: netignite-server\n    restart: unless-stopped\n    ports:\n      - \"18232:18232\"\n    environment:\n      NETIGNITE_APP_URL: https:\u002F\u002Fnetignite.example.com\n    volumes:\n      - \u002Fopt\u002Fnetignite\u002Fdata:\u002Fopt\u002Fnetignite\u002Fdata\n      - \u002Fopt\u002Fnetignite\u002Fconfig:\u002Fopt\u002Fnetignite\u002Fconfig\n","docker-compose.yml","yaml",[27,365,366,376,383,395,406,417,425,440,448,459,467,475],{"__ignoreMap":311},[315,367,368,372],{"class":317,"line":318},[315,369,371],{"class":370},"swJcz","services",[315,373,375],{"class":374},"sMK4o",":\n",[315,377,378,381],{"class":317,"line":332},[315,379,380],{"class":370},"  netignite-server",[315,382,375],{"class":374},[315,384,386,389,392],{"class":317,"line":385},3,[315,387,388],{"class":370},"    image",[315,390,391],{"class":374},":",[315,393,394],{"class":325}," ghcr.io\u002Fnetignite-project\u002Fserver:latest\n",[315,396,398,401,403],{"class":317,"line":397},4,[315,399,400],{"class":370},"    container_name",[315,402,391],{"class":374},[315,404,405],{"class":325}," netignite-server\n",[315,407,409,412,414],{"class":317,"line":408},5,[315,410,411],{"class":370},"    restart",[315,413,391],{"class":374},[315,415,416],{"class":325}," unless-stopped\n",[315,418,420,423],{"class":317,"line":419},6,[315,421,422],{"class":370},"    ports",[315,424,375],{"class":374},[315,426,428,431,434,437],{"class":317,"line":427},7,[315,429,430],{"class":374},"      -",[315,432,433],{"class":374}," \"",[315,435,436],{"class":325},"18232:18232",[315,438,439],{"class":374},"\"\n",[315,441,443,446],{"class":317,"line":442},8,[315,444,445],{"class":370},"    environment",[315,447,375],{"class":374},[315,449,451,454,456],{"class":317,"line":450},9,[315,452,453],{"class":370},"      NETIGNITE_APP_URL",[315,455,391],{"class":374},[315,457,458],{"class":325}," https:\u002F\u002Fnetignite.example.com\n",[315,460,462,465],{"class":317,"line":461},10,[315,463,464],{"class":370},"    volumes",[315,466,375],{"class":374},[315,468,470,472],{"class":317,"line":469},11,[315,471,430],{"class":374},[315,473,474],{"class":325}," \u002Fopt\u002Fnetignite\u002Fdata:\u002Fopt\u002Fnetignite\u002Fdata\n",[315,476,478,480],{"class":317,"line":477},12,[315,479,430],{"class":374},[315,481,482],{"class":325}," \u002Fopt\u002Fnetignite\u002Fconfig:\u002Fopt\u002Fnetignite\u002Fconfig\n",[305,484,486],{"className":307,"code":485,"filename":309,"language":310,"meta":311,"style":311},"docker compose pull\ndocker compose up -d\n",[27,487,488,497],{"__ignoreMap":311},[315,489,490,492,494],{"class":317,"line":318},[315,491,322],{"class":321},[315,493,326],{"class":325},[315,495,496],{"class":325}," pull\n",[315,498,499,501,503,506],{"class":317,"line":332},[315,500,322],{"class":321},[315,502,326],{"class":325},[315,504,505],{"class":325}," up",[315,507,508],{"class":325}," -d\n",[14,510,511,512,514,515,517,518,520],{},"v2 creates its own database ",[27,513,94],{}," next to the v1 ",[27,516,38],{},", and a new\n",[27,519,229],{}," with a password link. Don't use the link yet if you want the v1 admin password to carry over.",[14,522,523,524,184,526,529,530,532,533,54],{},"If you use a reverse proxy, check that it forwards WebSockets on ",[27,525,151],{},[27,527,528],{},"\u002Fws\u002Fconsole","\n(v1 only needed ",[27,531,145],{},"). See ",[46,534,536],{"href":535},"\u002Fdocs\u002Fserver\u002Freverse-proxy","HTTPS & Reverse Proxy",[192,538,49],{"id":539},"try-the-import",[14,541,542],{},"A dry run imports everything inside a transaction and rolls it back, so nothing changes:",[305,544,546],{"className":307,"code":545,"filename":309,"language":310,"meta":311,"style":311},"docker exec netignite-server bun \u002Fopt\u002Fnetignite\u002Fapp\u002F.output\u002Fimport-v1.mjs \\\n  --from \u002Fopt\u002Fnetignite\u002Fdata\u002Fdb.sqlite --dry-run\n",[27,547,548,568],{"__ignoreMap":311},[315,549,550,552,555,558,561,564],{"class":317,"line":318},[315,551,322],{"class":321},[315,553,554],{"class":325}," exec",[315,556,557],{"class":325}," netignite-server",[315,559,560],{"class":325}," bun",[315,562,563],{"class":325}," \u002Fopt\u002Fnetignite\u002Fapp\u002F.output\u002Fimport-v1.mjs",[315,565,567],{"class":566},"sTEyZ"," \\\n",[315,569,570,573,576],{"class":317,"line":332},[315,571,572],{"class":325},"  --from",[315,574,575],{"class":325}," \u002Fopt\u002Fnetignite\u002Fdata\u002Fdb.sqlite",[315,577,578],{"class":325}," --dry-run\n",[305,580,586],{"className":581,"code":583,"filename":584,"language":585,"meta":311},[582],"language-text","Dry run — nothing was changed.\n\nUsers imported: 2\nUsers merged:   admin\nAgents imported: 2\nDevices imported: 5\nFavorites imported: 3\nImported users got a placeholder email (…@imported.netignite.invalid) and are asked to change it after logging in.\n","Output","text",[27,587,583],{"__ignoreMap":311},[14,589,590,591,593,594,597,598,601],{},"Users whose username already exists in v2 (other than ",[27,592,229],{},") are skipped:\n",[27,595,596],{},"skipped user alice: username already exists in v2 (use --merge-users to merge them)",". With\n",[27,599,600],{},"--merge-users",", such a v1 user is merged into the existing v2 user instead; the v2 user takes over\nthe v1 password only if nobody has logged in to it in v2 yet.",[192,603,605],{"id":604},"import","Import",[305,607,609],{"className":307,"code":608,"filename":309,"language":310,"meta":311,"style":311},"docker exec netignite-server bun \u002Fopt\u002Fnetignite\u002Fapp\u002F.output\u002Fimport-v1.mjs \\\n  --from \u002Fopt\u002Fnetignite\u002Fdata\u002Fdb.sqlite\n",[27,610,611,625],{"__ignoreMap":311},[315,612,613,615,617,619,621,623],{"class":317,"line":318},[315,614,322],{"class":321},[315,616,554],{"class":325},[315,618,557],{"class":325},[315,620,560],{"class":325},[315,622,563],{"class":325},[315,624,567],{"class":566},[315,626,627,629],{"class":317,"line":332},[315,628,572],{"class":325},[315,630,631],{"class":325}," \u002Fopt\u002Fnetignite\u002Fdata\u002Fdb.sqlite\n",[14,633,634,635,637,638,640,641,54],{},"The import uses the container's ",[27,636,130],{}," settings and writes to the running server's\ndatabase. Running it again is safe: records that were already imported are skipped. When the\n",[27,639,229],{}," takes over the v1 password, the import deletes ",[27,642,115],{},[14,644,645,646,54],{},"Running the server from source? Run the import from the repository root:\n",[27,647,648],{},"bun scripts\u002Fimport-v1.ts --from \u003Cpath to db.sqlite> [--dry-run] [--merge-users]",[192,650,652],{"id":651},"log-in","Log in",[14,654,655,656,658,659,54],{},"Log in as ",[27,657,229],{}," with the v1 password (or, if you set a v2 password with the link before the\nimport, with that one). Every user gets the welcome page at the first login; ask your users to enter their real\nemail address under ",[23,660,661],{},"Settings → General",[192,663,665],{"id":664},"set-up-the-agents-again","Set up the agents again",[14,667,668,669,671,672,674],{},"Open ",[23,670,243],{},". The imported agents show ",[23,673,253],{},"; their devices still point at them.",[676,677,678,702],"ul",{},[679,680,681,684,685,688,689,693,694,698,699,701],"li",{},[23,682,683],{},"ESP32 boards"," need the v2 firmware once over USB: open the agent's ",[23,686,687],{},"Install"," tab and follow\nthe ",[46,690,692],{"href":691},"\u002Fdocs\u002Fagents\u002Fesp32#install-from-the-browser","web installer",". v2 uses a new partition table\nwith two firmware slots, so it can't be installed over the network on a v1 board. After that,\nupdates come ",[46,695,697],{"href":696},"\u002Fdocs\u002Fguides\u002Fagents#firmware-updates","over the network",". Your old ",[27,700,162],{}," isn't\nneeded anymore: the installer sets the server and the Wi-Fi.",[679,703,704,707,708,712,713,717],{},[23,705,706],{},"Server agents"," (your own v1 agents) don't work with v2: the\n",[46,709,711],{"href":710},"\u002Fdocs\u002Fagents\u002Fprotocol","protocol"," changed. Install the ",[46,714,716],{"href":715},"\u002Fdocs\u002Fagents\u002Flinux","Linux agent"," on the\nmachine instead (turn on Wake-on-LAN mode to wake other devices), or update your agent to\nprotocol v2.",[14,719,720],{},"As each agent comes online, its devices can be woken again.",[192,722,724],{"id":723},"check-the-devices","Check the devices",[14,726,727,728,732,733,737,738,741,742,54],{},"The imported devices keep the v1 status check, which doesn't work for most Windows and many Linux\nmachines. Open each device and choose a better ",[46,729,731],{"href":730},"\u002Fdocs\u002Fguides\u002Fdevices#status-checks","status check",",\nfor example its IPv4 address. While you're there, consider ",[46,734,736],{"href":735},"\u002Fdocs\u002Fguides\u002Fsharing","sharing",",\nshutdown through the ",[46,739,716],{"href":740},"\u002Fdocs\u002Fagents\u002Flinux#host-mode"," or over ",[46,743,745],{"href":744},"\u002Fdocs\u002Fguides\u002Fssh","SSH",[192,747,749],{"id":748},"going-back","Going back",[14,751,752,753,755,756,758],{},"The v1 database ",[27,754,38],{}," is never modified. To go back, run the v1 image again (for example\n",[27,757,53],{},") with the same volumes. Agents you set up for v2 don't\nwork with v1: flash the v1 firmware onto ESP32 boards again.",[14,760,761,762,177,764,766,767,54],{},"Once you're happy with v2, you can delete ",[27,763,38],{},[27,765,109],{}," and\n",[27,768,125],{},[770,771,772],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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 .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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":311,"searchDepth":332,"depth":332,"links":774},[775,776,777,778,779,780,781,782,783],{"id":194,"depth":332,"text":195},{"id":299,"depth":332,"text":300},{"id":350,"depth":332,"text":351},{"id":539,"depth":332,"text":49},{"id":604,"depth":332,"text":605},{"id":651,"depth":332,"text":652},{"id":664,"depth":332,"text":665},{"id":723,"depth":332,"text":724},{"id":748,"depth":332,"text":749},"Move a NetIgnite v1 server to v2: back up, run v2 next to the v1 data, import users, agents and devices, and set the agents up again.","md",{},{"title":5},"\u002Fdocs\u002Fserver\u002Fupgrading",{"title":5,"description":784},"docs\u002Fserver\u002Fupgrading","vwsNSPkM5pSJBnY8m83hR7LanjV_xdMCJyAvQPHyMUQ",1792614952936]