[{"data":1,"prerenderedAt":509},["ShallowReactive",2],{"nav-docs":3,"nav-api":60,"docs-index":89},[4],{"title":5,"path":6,"stem":7,"children":8},"Docs","\u002Fdocs","docs",[9,12,16,20,24,28,32,36,40,44,48,52,56],{"title":10,"path":6,"stem":11},"Installation","docs\u002Findex",{"title":13,"path":14,"stem":15},"Sending files","\u002Fdocs\u002Fsending-files","docs\u002F02.sending-files",{"title":17,"path":18,"stem":19},"Receiving files","\u002Fdocs\u002Freceiving-files","docs\u002F03.receiving-files",{"title":21,"path":22,"stem":23},"Passwords, galleries and backgrounds","\u002Fdocs\u002Fshare-options","docs\u002F04.share-options",{"title":25,"path":26,"stem":27},"Expiry and deletion","\u002Fdocs\u002Fexpiry","docs\u002F05.expiry",{"title":29,"path":30,"stem":31},"Users","\u002Fdocs\u002Fusers","docs\u002F06.users",{"title":33,"path":34,"stem":35},"Configuration","\u002Fdocs\u002Fconfiguration","docs\u002F07.configuration",{"title":37,"path":38,"stem":39},"Colours and branding","\u002Fdocs\u002Fcolors","docs\u002F08.colors",{"title":41,"path":42,"stem":43},"Docker","\u002Fdocs\u002Fdocker","docs\u002F09.docker",{"title":45,"path":46,"stem":47},"API keys","\u002Fdocs\u002Fapi-keys","docs\u002F10.api-keys",{"title":49,"path":50,"stem":51},"MCP server","\u002Fdocs\u002Fmcp-server","docs\u002F11.mcp-server",{"title":53,"path":54,"stem":55},"Troubleshooting","\u002Fdocs\u002Ftroubleshooting","docs\u002F12.troubleshooting",{"title":57,"path":58,"stem":59},"Contributing","\u002Fdocs\u002Fcontributing","docs\u002F13.contributing",[61],{"title":62,"path":63,"stem":64,"children":65},"Api","\u002Fapi","api",[66,69,73,77,81,85],{"title":67,"path":63,"stem":68},"REST API","api\u002Findex",{"title":70,"path":71,"stem":72},"Transfers","\u002Fapi\u002Ftransfers","api\u002F02.transfers",{"title":74,"path":75,"stem":76},"Uploading files","\u002Fapi\u002Fupload","api\u002F03.upload",{"title":78,"path":79,"stem":80},"Sending a transfer","\u002Fapi\u002Fsend","api\u002F04.send",{"title":82,"path":83,"stem":84},"Downloading","\u002Fapi\u002Fdownload","api\u002F05.download",{"title":86,"path":87,"stem":88},"Recipients","\u002Fapi\u002Frecipients","api\u002F06.recipients",{"id":90,"title":10,"body":91,"description":101,"extension":504,"meta":505,"navigation":506,"path":6,"seo":507,"stem":11,"__hash__":508},"docs\u002Fdocs\u002Findex.md",{"type":92,"value":93,"toc":498},"minimark",[94,98,102,105,110,113,223,226,241,245,248,291,302,305,345,348,352,355,362,403,410,416,434,445,451,455,458,494],[95,96,10],"h1",{"id":97},"installation",[99,100,101],"p",{},"LokalTransfer is a self-hosted file transfer service. You run it on your own\nserver, and nothing about a transfer — the files, the recipients, the link —\ntouches anybody else's infrastructure.",[99,103,104],{},"There are two ways to install it. Docker is the short one.",[106,107,109],"h2",{"id":108},"with-docker","With Docker",[99,111,112],{},"The published image carries its own MySQL 8, so there is nothing to set up\nfirst:",[114,115,120],"pre",{"className":116,"code":117,"language":118,"meta":119,"style":119},"language-bash shiki shiki-themes github-light github-dark","docker run -d \\\n  --name lokaltransfer \\\n  -p 3000:3000 \\\n  -v lokaltransfer-storage:\u002Fapp\u002Fstorage \\\n  -v lokaltransfer-db:\u002Fvar\u002Flib\u002Fmysql \\\n  -e NUXT_APP_URL=https:\u002F\u002Ftransfer.example.com \\\n  -e NUXT_ADMIN_EMAIL=you@example.com \\\n  -e NUXT_ADMIN_PASSWORD=a-long-password \\\n  florianstrasser\u002Flokaltransfer:latest\n","bash","",[121,122,123,143,154,165,176,186,197,207,217],"code",{"__ignoreMap":119},[124,125,128,132,136,140],"span",{"class":126,"line":127},"line",1,[124,129,131],{"class":130},"sScJk","docker",[124,133,135],{"class":134},"sZZnC"," run",[124,137,139],{"class":138},"sj4cs"," -d",[124,141,142],{"class":138}," \\\n",[124,144,146,149,152],{"class":126,"line":145},2,[124,147,148],{"class":138},"  --name",[124,150,151],{"class":134}," lokaltransfer",[124,153,142],{"class":138},[124,155,157,160,163],{"class":126,"line":156},3,[124,158,159],{"class":138},"  -p",[124,161,162],{"class":134}," 3000:3000",[124,164,142],{"class":138},[124,166,168,171,174],{"class":126,"line":167},4,[124,169,170],{"class":138},"  -v",[124,172,173],{"class":134}," lokaltransfer-storage:\u002Fapp\u002Fstorage",[124,175,142],{"class":138},[124,177,179,181,184],{"class":126,"line":178},5,[124,180,170],{"class":138},[124,182,183],{"class":134}," lokaltransfer-db:\u002Fvar\u002Flib\u002Fmysql",[124,185,142],{"class":138},[124,187,189,192,195],{"class":126,"line":188},6,[124,190,191],{"class":138},"  -e",[124,193,194],{"class":134}," NUXT_APP_URL=https:\u002F\u002Ftransfer.example.com",[124,196,142],{"class":138},[124,198,200,202,205],{"class":126,"line":199},7,[124,201,191],{"class":138},[124,203,204],{"class":134}," NUXT_ADMIN_EMAIL=you@example.com",[124,206,142],{"class":138},[124,208,210,212,215],{"class":126,"line":209},8,[124,211,191],{"class":138},[124,213,214],{"class":134}," NUXT_ADMIN_PASSWORD=a-long-password",[124,216,142],{"class":138},[124,218,220],{"class":126,"line":219},9,[124,221,222],{"class":134},"  florianstrasser\u002Flokaltransfer:latest\n",[99,224,225],{},"Both volumes matter. Without them the uploads and the database live in the\ncontainer's own layer and disappear the first time you recreate it.",[99,227,228,229,232,233,236,237,240],{},"If you already run a database, set ",[121,230,231],{},"NUXT_MYSQL_HOST"," and the built-in one never\nstarts. See ",[234,235,41],"a",{"href":42}," for the full picture, including\n",[121,238,239],{},"docker compose",".",[106,242,244],{"id":243},"from-source","From source",[99,246,247],{},"Requires Node 20+ and a MySQL 8 database.",[114,249,251],{"className":116,"code":250,"language":118,"meta":119,"style":119},"git clone https:\u002F\u002Fgithub.com\u002Fflorian-strasser\u002FLokalTransfer.git\ncd LokalTransfer\npnpm install\ncp .env.example .env\n",[121,252,253,264,272,280],{"__ignoreMap":119},[124,254,255,258,261],{"class":126,"line":127},[124,256,257],{"class":130},"git",[124,259,260],{"class":134}," clone",[124,262,263],{"class":134}," https:\u002F\u002Fgithub.com\u002Fflorian-strasser\u002FLokalTransfer.git\n",[124,265,266,269],{"class":126,"line":145},[124,267,268],{"class":138},"cd",[124,270,271],{"class":134}," LokalTransfer\n",[124,273,274,277],{"class":126,"line":156},[124,275,276],{"class":130},"pnpm",[124,278,279],{"class":134}," install\n",[124,281,282,285,288],{"class":126,"line":167},[124,283,284],{"class":130},"cp",[124,286,287],{"class":134}," .env.example",[124,289,290],{"class":134}," .env\n",[99,292,293,294,297,298,301],{},"Fill in ",[121,295,296],{},".env"," — at minimum the database and SMTP credentials, and\n",[121,299,300],{},"NUXT_APP_URL",". That last one is not optional in production: download and\nsign-in links are built from it, so if it is wrong every link you send is wrong.",[99,303,304],{},"Create the database and start the app:",[114,306,308],{"className":116,"code":307,"language":118,"meta":119,"style":119},"mysql -u root -p -e \"CREATE DATABASE lokaltransfer CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\"\npnpm build\nnode .output\u002Fserver\u002Findex.mjs\n",[121,309,310,330,337],{"__ignoreMap":119},[124,311,312,315,318,321,324,327],{"class":126,"line":127},[124,313,314],{"class":130},"mysql",[124,316,317],{"class":138}," -u",[124,319,320],{"class":134}," root",[124,322,323],{"class":138}," -p",[124,325,326],{"class":138}," -e",[124,328,329],{"class":134}," \"CREATE DATABASE lokaltransfer CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\"\n",[124,331,332,334],{"class":126,"line":145},[124,333,276],{"class":130},[124,335,336],{"class":134}," build\n",[124,338,339,342],{"class":126,"line":156},[124,340,341],{"class":130},"node",[124,343,344],{"class":134}," .output\u002Fserver\u002Findex.mjs\n",[99,346,347],{},"The schema is created on first start. There is no separate migration command to\nremember.",[106,349,351],{"id":350},"the-first-administrator","The first administrator",[99,353,354],{},"There is no public sign-up, so a fresh instance cannot create its first account\nthrough the interface. Seed one of two ways.",[99,356,357,361],{},[358,359,360],"strong",{},"From the environment"," — best for containers and managed hosts:",[114,363,365],{"className":116,"code":364,"language":118,"meta":119,"style":119},"NUXT_ADMIN_NAME=Your Name\nNUXT_ADMIN_EMAIL=you@example.com\nNUXT_ADMIN_PASSWORD=a-long-password\n",[121,366,367,383,393],{"__ignoreMap":119},[124,368,369,373,377,380],{"class":126,"line":127},[124,370,372],{"class":371},"sVt8B","NUXT_ADMIN_NAME",[124,374,376],{"class":375},"szBVR","=",[124,378,379],{"class":134},"Your",[124,381,382],{"class":130}," Name\n",[124,384,385,388,390],{"class":126,"line":145},[124,386,387],{"class":371},"NUXT_ADMIN_EMAIL",[124,389,376],{"class":375},[124,391,392],{"class":134},"you@example.com\n",[124,394,395,398,400],{"class":126,"line":156},[124,396,397],{"class":371},"NUXT_ADMIN_PASSWORD",[124,399,376],{"class":375},[124,401,402],{"class":134},"a-long-password\n",[99,404,405,406,409],{},"The account is created on startup. This only ever acts when the instance has\n",[358,407,408],{},"no administrator at all",", so a password you later change in the app is never\nreverted, and the variables are safe to leave configured — they double as a\nrecovery hatch if the last admin is ever deleted.",[99,411,412,415],{},[358,413,414],{},"From the shell"," — best for a local or hand-managed install:",[114,417,419],{"className":116,"code":418,"language":118,"meta":119,"style":119},"pnpm create-admin \"Your Name\" you@example.com\n",[121,420,421],{"__ignoreMap":119},[124,422,423,425,428,431],{"class":126,"line":127},[124,424,276],{"class":130},[124,426,427],{"class":134}," create-admin",[124,429,430],{"class":134}," \"Your Name\"",[124,432,433],{"class":134}," you@example.com\n",[99,435,436,437,440,441,444],{},"It asks for the password at a hidden prompt, or takes it from ",[121,438,439],{},"ADMIN_PASSWORD","\nfor an unattended run. It is deliberately not accepted as a command-line\nargument and never printed: argv is visible to ",[121,442,443],{},"ps"," for every user on the\nmachine and recorded in shell history, and anything printed lands in whatever is\ncapturing the output.",[99,446,447,448,450],{},"Every account after the first is created from ",[358,449,29],{}," in the app.",[106,452,454],{"id":453},"behind-a-reverse-proxy","Behind a reverse proxy",[99,456,457],{},"Two settings catch people out:",[459,460,461,476],"ul",{},[462,463,464,467,468,471,472,475],"li",{},[358,465,466],{},"Raise the body limit."," nginx defaults ",[121,469,470],{},"client_max_body_size"," to 1 MB and\nwill reject uploads long before the app sees them. Match it to\n",[121,473,474],{},"NUXT_MAX_FILE_SIZE_MB",", and raise the read timeouts while you are there.",[462,477,478,481,482,485,486,489,490,493],{},[358,479,480],{},"Forward the protocol."," Session cookies are marked ",[121,483,484],{},"secure"," when\n",[121,487,488],{},"NODE_ENV=production"," or when ",[121,491,492],{},"X-Forwarded-Proto: https"," is present. Without\none of those, a browser on HTTPS discards the cookie and sign-in appears to do\nnothing.",[495,496,497],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":119,"searchDepth":145,"depth":145,"links":499},[500,501,502,503],{"id":108,"depth":145,"text":109},{"id":243,"depth":145,"text":244},{"id":350,"depth":145,"text":351},{"id":453,"depth":145,"text":454},"md",{},true,{"title":10,"description":101},"RZHqmcxj8nEUZ8VMEk-trBUYI4mY4Qe_FPamVeX0Z0g",1790104591762]