PageSourceSearch

https://doc.elabftw.net/assets/js/23f3e29c.2cf43e04.js

js elabftw.net collected 2026-09-25 02:55:10 UTC 15,849 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkelabftw_documentation=self.webpackChunkelabftw_documentation||[]).push([["8459"],{3315(e,n,i){i.r(n),i.d(n,{metadata:()=>s,default:()=>h,frontMatter:()=>o,contentTitle:()=>l,toc:()=>d,assets:()=>a});var s=JSON.parse('{"id":"install/upgrade/update-6","title":"Upgrade from v5 to v6","description":"eLabFTW version 6 introduces a few breaking changes impacting container deployment. This page will guide you through the changes.","source":"@site/versioned_docs/version-6.0/install/upgrade/update-6.md","sourceDirName":"install/upgrade","slug":"/install/upgrade/update-6","permalink":"/docs/install/upgrade/update-6","draft":false,"unlisted":false,"editUrl":"https://github.com/elabftw/elabftw/edit/release/6.0/documentation/docs/install/upgrade/update-6.md","tags":[],"version":"6.0","sidebarPosition":5,"frontMatter":{"sidebar_position":5,"title":"Upgrade from v5 to v6"},"sidebar":"installSidebar","previous":{"title":"Upgrade your instance","permalink":"/docs/install/upgrade/update"},"next":{"title":"Backups","permalink":"/docs/install/backups"}}'),r=i(4848),t=i(8453);let o={sidebar_position:5,title:"Upgrade from v5 to v6"},l="How to upgrade from version 5.x to version 6.0",a={},d=[{value:"Overview",id:"overview",level:2},{value:"Making backups",id:"making-backups",level:2},{value:"Creating a dedicated user",id:"creating-a-dedicated-user",level:2},{value:"Changes to the configuration file",id:"changes-to-the-configuration-file",level:2},{value:"Docker",id:"docker",level:3},{value:"Quadlets",id:"quadlets",level:3},{value:"Volumes",id:"volumes",level:3},{value:"Cache folder",id:"cache-folder",level:4},{value:"Uploads folder",id:"uploads-folder",level:4},{value:"Exports folder",id:"exports-folder",level:4},{value:"Summary for volumes",id:"summary-for-volumes",level:4},{value:"Same thing for Quadlets",id:"same-thing-for-quadlets",level:5},{value:"TLS Certificates",id:"tls-certificates",level:3},{value:"Ports",id:"ports",level:3},{value:"Environment",id:"environment",level:3},{value:"No IPV6 in container",id:"no-ipv6-in-container",level:3},{value:"Chem-plugin",id:"chem-plugin",level:3},{value:"OpenCloning in Quadlets",id:"opencloning-in-quadlets",level:3},{value:"MySQL Persistent connection mode",id:"mysql-persistent-connection-mode",level:3},{value:"NGINX access logs now use structured JSON",id:"nginx-access-logs-now-use-structured-json",level:3},{value:"MySQL 8.4 becomes the minimum supported version",id:"mysql-84-becomes-the-minimum-supported-version",level:3}];function c(e){let n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"how-to-upgrade-from-version-5x-to-version-60",children:"How to upgrade from version 5.x to version 6.0"})}),"\n",(0,r.jsx)(n.p,{children:"eLabFTW version 6 introduces a few breaking changes impacting container deployment. This page will guide you through the changes."}),"\n",(0,r.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,r.jsx)(n.p,{children:"Here are the main changes:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"container port change"}),"\n",(0,r.jsx)(n.li,{children:"container volumes change"}),"\n",(0,r.jsx)(n.li,{children:"container user configuration change"}),"\n",(0,r.jsx)(n.li,{children:"container certificates paths"}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["Note: this guide assumes usage of ",(0,r.jsx)(n.code,{children:"docker compose"}),", with hints related to ",(0,r.jsx)(n.code,{children:"podman/quadlets"})," (podman is another container engine and quadlets are systemd-managed container unit files). For other deployments, you will need to adapt the changes to your context."]}),"\n",(0,r.jsx)(n.h2,{id:"making-backups",children:"Making backups"}),"\n",(0,r.jsx)(n.p,{children:"Make a backup of your configuration file:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# docker\ncp /etc/elabftw.yml /etc/elabftw.yml.v5.bak\n"})}),"\n",(0,r.jsx)(n.p,{children:"Obviously, make sure your data backups are also functional and recent before attempting upgrade. But that is valid for any upgrade."}),"\n",(0,r.jsx)(n.h2,{id:"creating-a-dedicated-user",children:"Creating a dedicated user"}),"\n",(0,r.jsx)(n.p,{children:"Create a dedicated user that will run the services:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"useradd --system --no-create-home --shell /usr/sbin/nologin elabftw-worker\nid elabftw-worker\n"})}),"\n",(0,r.jsx)(n.p,{children:"Note the user id and group id of that newly created user shown by the second command."}),"\n",(0,r.jsx)(n.h2,{id:"changes-to-the-configuration-file",children:"Changes to the configuration file"}),"\n",(0,r.jsxs)(n.p,{children:["In your configuration file (by default ",(0,r.jsx)(n.code,{children:"/etc/elabftw.yml"}),", start by setting the version of the image:"]}),"\n",(0,r.jsx)(n.h3,{id:"docker",children:"Docker"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"image: elabftw/elabimg:6.0.0\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Next, add these lines below ",(0,r.jsx)(n.code,{children:"image:"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"# this could look like: user: 995:981\nuser: <REPLACE WITH ELABFTW-WORKER UID>:<REPLACE WITH ELABFTW-WORKER GID>\nread_only: true\ntmpfs:\n  - /run:mode=755,uid=<REPLACE WITH ELABFTW-WORKER UID>,gid=<REPLACE WITH ELABFTW-WORKER GID>,exec,nosuid,nodev,size=64m\n"})}),"\n",(0,r.jsxs)(n.p,{children:["This will make the container start and run with ",(0,r.jsx)(n.code,{children:"elabftw-worker"})," user, and a read-only filesystem."]}),"\n",(0,r.jsx)(n.h3,{id:"quadlets",children:"Quadlets"}),"\n",(0,r.jsxs)(n.p,{children:["Ignore this section if you use ",(0,r.jsx)(n.code,{children:"docker 
1compose"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"Only changed/added lines are shown:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-conf",children:"[Container]\nImage=docker.io/elabftw/elabimg:6.0.0\nReadOnly=true\nUserNS=keep-id\nHealthCmd=wget --quiet --spider http://localhost:8080/healthcheck\nMount=type=tmpfs,destination=/run,U=true,tmpfs-mode=0755,notmpcopyup,tmpfs-size=64m\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Move the file into ",(0,r.jsx)(n.code,{children:"${XDG_CONFIG_HOME:-$HOME/.config}/containers/systemd/"})," for your user."]}),"\n",(0,r.jsx)(n.p,{children:"See also sections below, adjust volumes accordingly."}),"\n",(0,r.jsx)(n.h3,{id:"volumes",children:"Volumes"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"volumes:"})," section needs to be adjusted."]}),"\n",(0,r.jsx)(n.h4,{id:"cache-folder",children:"Cache folder"}),"\n",(0,r.jsxs)(n.p,{children:["We will add a folder specific for cached files that the application will need to create. First, we create it on the host and allow our ",(0,r.jsx)(n.code,{children:"elabftw-worker"})," user to write to it:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"mkdir -p /var/cache/elabftw\nchown elabftw-worker:elabftw-worker /var/cache/elabftw\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Then in the configuration file, under ",(0,r.jsx)(n.code,{children:"volumes:"})," section:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"volumes:\n  - /var/cache/elabftw:/var/cache/elabftw\n"})}),"\n",(0,r.jsx)(n.h4,{id:"uploads-folder",children:"Uploads folder"}),"\n",(0,r.jsx)(n.p,{children:"Change this line:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"- /var/elabftw/web:/elabftw/uploads\n"})}),"\n",(0,r.jsx)(n.p,{children:"To this line:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"- /var/elabftw/web:/var/lib/elabftw/uploads\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Note: first part might differ on your setup obviously. The main point is that the uploaded files are now expected to be in ",(0,r.jsx)(n.code,{children:"/var/lib/elabftw/uploads"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"Adjust the ownership with our new user:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"chown -R elabftw-worker:elabftw-worker /var/elabftw/web\n"})}),"\n",(0,r.jsx)(n.h4,{id:"exports-folder",children:"Exports folder"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"exports"})," folder will hold the files generated by the Export function of eLabFTW. It must also be bind-mounted on the host. It is possible that you did not bind-mount that folder previously, as it wasn't a strict requirement. So if you don't see the line, add it."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"- /var/elabftw/exports:/var/lib/elabftw/exports\n"})}),"\n",(0,r.jsxs)(n.p,{children:["If the line was present, change ",(0,r.jsx)(n.code,{children:"/elabftw/exports"})," to ",(0,r.jsx)(n.code,{children:"/var/lib/elabftw/exports"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"Adjust the ownership with our new user:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"chown -R elabftw-worker:elabftw-worker /var/elabftw/exports\n"})}),"\n",(0,r.jsx)(n.h4,{id:"summary-for-volumes",children:"Summary for volumes"}),"\n",(0,r.jsxs)(n.p,{children:["The whole ",(0,r.jsx)(n.code,{children:"volumes"})," section should then look like:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"volumes:\n  - /var/cache/elabftw:/var/cache/elabftw\n  - /var/elabftw/web:/var/lib/elabftw/uploads\n  - /var/elabftw/exports:/var/lib/elabftw/exports\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Make sure the ",(0,r.jsx)(n.code,{children:"elabftw-worker"})," user can write to these folders."]}),"\n",(0,r.jsx)(n.h5,{id:"same-thing-for-quadlets",children:"Same thing for Quadlets"}),"\n",(0,r.jsx)(n.p,{children:"This is a Quadlets example, ignore this section if you use Docker Compose."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-conf",children:"[Container]\nVolume=/var/cache/elabftw:/var/cache/elabftw:Z\nVolume=/var/elabftw/web:/var/lib/elabftw/uploads:Z\nVolume=/var/elabftw/exports:/var/lib/elabftw/exports:Z\n"})}),"\n",(0,r.jsx)(n.h3,{id:"tls-certificates",children:"TLS Certificates"}),"\n",(0,r.jsxs)(n.p,{children:["If you are running the container in HTTPS mode (meaning ",(0,r.jsx)(n.code,{children:"DISABLE_HTTPS"})," is ",(0,r.jsx)(n.code,{children:"false"}),", the default), then you need to modify env and volumes. The cert and key are now indicated by ",(0,r.jsx)(n.code,{children:"TLS_CERT_PATH"})," and ",(0,r.jsx)(n.code,{children:"TLS_KEY_PATH"})," env vars."]}),"\n",(0,r.jsxs)(n.p,{children:["Read the documentation about TLS configuration from this page: ",(0,r.jsx)(n.a,{href:"../installation/tls#option-b-https-mode-with-lets-encrypt-certificates",children:"TLS configuration doc"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"ports",children:"Ports"}),"\n",(0,r.jsxs)(n.p,{children:["In the ",(0,r.jsx)(n.code,{children:"ports:"})," section, we will need to change internal port ",(0,r.jsx)(n.code,{children:"443"})," to ",(0,r.jsx)(n.code,{children:"8080"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"Change this line:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"ports:\n  - '443:443'\n"})}),"\n",(0,r.jsx)(n.p,{children:"To this line:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"ports:\n  - '443:8080'\n"})}),"\n",(0,r.jsx)(n.p,{children:"It is the right-hand side that needs to be modified: the listening port in the container."}),"\n",(0,r.jsx)(n.p,{children:"For Quadlets, adjust PublishPort if you're using this, or adjust your reverse proxy to use port 8080."}),"\n",(0,r.jsx)(n.h3,{id:"environment",children:"Environment"}),"\n",(0,r.jsx)(n.p,{children:"Some environment variables are no longer relevant, and should be removed from your configuration. Remove these environment variables:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"ENABLE_IPV6\nELABFTW_USER\nELABFTW_GROUP\nELABFTW_USERID\nELABFTW_GROUPID\nINDIGO_URL\nENABLE_LETSENCRYPT\nSERVER_NAME\nSILENT_INIT\nUSE_INDIGO\nUSE_FINGERPRINTE
1R\nFINGERPRINTER_URL\nFINGERPRINTER_USE_PROXY\n"})}),"\n",(0,r.jsx)(n.h3,{id:"no-ipv6-in-container",children:"No IPV6 in container"}),"\n",(0,r.jsxs)(n.p,{children:["We removed support for IPv6 in container. You can still use IPv6 to expose the service to the outside world, but the ",(0,r.jsx)(n.code,{children:"nginx"})," process inside the container doesn't need to listen on IPv6 network stack."]}),"\n",(0,r.jsx)(n.h3,{id:"chem-plugin",children:"Chem-plugin"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"chem-plugin"})," addon can now be completely removed! It is not useful anymore:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"indigo/ketcher code is now running in the browser through WASM worker"}),"\n",(0,r.jsx)(n.li,{children:"openbabel code for compound fingerprinting is now running in the main container"}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["It is then safe to remove the whole ",(0,r.jsx)(n.code,{children:"chem-plugin"})," block in your docker compose file."]}),"\n",(0,r.jsx)(n.h3,{id:"opencloning-in-quadlets",children:"OpenCloning in Quadlets"}),"\n",(0,r.jsx)(n.p,{children:"If you are running OpenCloning as a user with Quadlets, make sure to add:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.code,{children:"Environment=GUNICORN_CMD_ARGS=--wor
1ker-tmp-dir=/dev/shm --no-control-socket"})}),"\n",(0,r.jsx)(n.p,{children:"Or the worker will die when a request arrives."}),"\n",(0,r.jsx)(n.h3,{id:"mysql-persistent-connection-mode",children:"MySQL Persistent connection mode"}),"\n",(0,r.jsxs)(n.p,{children:["The environment variable ",(0,r.jsx)(n.code,{children:"USE_PERSISTENT_MYSQL_CONN"})," now defaults to ",(0,r.jsx)(n.code,{children:"false"}),". It used to be ",(0,r.jsx)(n.code,{children:"true"})," by default but that caused more issues than it solved, so now it's set to ",(0,r.jsx)(n.code,{children:"false"}),". This will have an impact if you did not set that value but expected it to be ",(0,r.jsx)(n.code,{children:"true"})," for some reason. If that's the case, then add it explicitly."]}),"\n",(0,r.jsx)(n.h3,{id:"nginx-access-logs-now-use-structured-json",children:"NGINX access logs now use structured JSON"}),"\n",(0,r.jsx)(n.p,{children:"The default NGINX access log format has been replaced with a structured JSON format providing significantly more diagnostic information, including request IDs, request and upstream response timings, response sizes, connection information, and compression ratios. Administrators parsing NGINX access logs should update their log-processing configuration accordingly."}),"\n",(0,r.jsx)(n.h3,{id:"mysql-84-becomes-the-minimum-supported-version",children:"MySQL 8.4 becomes the minimum supported version"}),"\n",(0,r.jsx)(n.p,{children:"MySQL 8.0 reached its official end-of-life (EOL) on April 30, 2026. eLabFTW version 6 requires running MySQL 8.4 as it uses features available only in this version."})]})}function h(e={}){let{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453(e,n,i){i.d(n,{R:()=>o,x:()=>l});var s=i(6540);let r={},t=s.createContext(r);function o(e){let n=s.useContext(t);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.