listmonk/docs/upgrade/index.html
github-actions[bot] 1e1764bddf deploy: ea88b94413
2025-09-03 05:53:45 +00:00

1415 lines
No EOL
29 KiB
HTML

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="prev" href="../configuration/">
<link rel="next" href="../concepts/">
<link rel="icon" href="../images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.18">
<title>Upgrade - listmonk / Documentation</title>
<link rel="stylesheet" href="../assets/stylesheets/main.7e37652d.min.css">
<link rel="stylesheet" href="../assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="../static/style.css">
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="white" data-md-color-accent="red">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#upgrade" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href=".." title="listmonk / Documentation" class="md-header__button md-logo" aria-label="listmonk / Documentation" data-md-component="logo">
<img src="../images/favicon.png" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
listmonk / Documentation
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Upgrade
</span>
</div>
</div>
</div>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href=".." title="listmonk / Documentation" class="md-nav__button md-logo" aria-label="listmonk / Documentation" data-md-component="logo">
<img src="../images/favicon.png" alt="logo">
</a>
listmonk / Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." class="md-nav__link">
<span class="md-ellipsis">
Introduction
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" checked>
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="">
<span class="md-ellipsis">
Getting Started
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Getting Started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../installation/" class="md-nav__link">
<span class="md-ellipsis">
Installation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../configuration/" class="md-nav__link">
<span class="md-ellipsis">
Configuration
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Upgrade
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Upgrade
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#binary" class="md-nav__link">
<span class="md-ellipsis">
Binary
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#docker" class="md-nav__link">
<span class="md-ellipsis">
Docker
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#railway" class="md-nav__link">
<span class="md-ellipsis">
Railway
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#downgrade" class="md-nav__link">
<span class="md-ellipsis">
Downgrade
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#upgrading-to-v4xx" class="md-nav__link">
<span class="md-ellipsis">
Upgrading to v4.x.x
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" >
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="">
<span class="md-ellipsis">
Using listmonk
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Using listmonk
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../concepts/" class="md-nav__link">
<span class="md-ellipsis">
Concepts
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../templating/" class="md-nav__link">
<span class="md-ellipsis">
Templating
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../querying-and-segmentation/" class="md-nav__link">
<span class="md-ellipsis">
Querying and segmenting subscribers
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../bounces/" class="md-nav__link">
<span class="md-ellipsis">
Bounce processing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../messengers/" class="md-nav__link">
<span class="md-ellipsis">
Messengers
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../archives/" class="md-nav__link">
<span class="md-ellipsis">
Archives
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../i18n/" class="md-nav__link">
<span class="md-ellipsis">
Internationalization
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../external-integration/" class="md-nav__link">
<span class="md-ellipsis">
Integrating with external systems
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../roles-and-permissions/" class="md-nav__link">
<span class="md-ellipsis">
User roles and permissions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../oidc/" class="md-nav__link">
<span class="md-ellipsis">
OIDC SSO
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="">
<span class="md-ellipsis">
API
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
API
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../apis/apis/" class="md-nav__link">
<span class="md-ellipsis">
Introduction
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../apis/sdks/" class="md-nav__link">
<span class="md-ellipsis">
SDKs and libs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../apis/subscribers/" class="md-nav__link">
<span class="md-ellipsis">
Subscribers
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../apis/lists/" class="md-nav__link">
<span class="md-ellipsis">
Lists
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../apis/import/" class="md-nav__link">
<span class="md-ellipsis">
Import
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../apis/campaigns/" class="md-nav__link">
<span class="md-ellipsis">
Campaigns
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../apis/media/" class="md-nav__link">
<span class="md-ellipsis">
Media
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../apis/templates/" class="md-nav__link">
<span class="md-ellipsis">
Templates
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../apis/transactional/" class="md-nav__link">
<span class="md-ellipsis">
Transactional
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../apis/bounces/" class="md-nav__link">
<span class="md-ellipsis">
Bounces
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="">
<span class="md-ellipsis">
Maintenance
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Maintenance
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../maintenance/performance/" class="md-nav__link">
<span class="md-ellipsis">
Performance
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="">
<span class="md-ellipsis">
Contributions
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Contributions
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../developer-setup/" class="md-nav__link">
<span class="md-ellipsis">
Developer setup
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#binary" class="md-nav__link">
<span class="md-ellipsis">
Binary
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#docker" class="md-nav__link">
<span class="md-ellipsis">
Docker
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#railway" class="md-nav__link">
<span class="md-ellipsis">
Railway
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#downgrade" class="md-nav__link">
<span class="md-ellipsis">
Downgrade
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#upgrading-to-v4xx" class="md-nav__link">
<span class="md-ellipsis">
Upgrading to v4.x.x
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="upgrade">Upgrade<a class="headerlink" href="#upgrade" title="Permanent link">&para;</a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Always take a backup of the Postgres database before upgrading listmonk</p>
</div>
<h2 id="binary">Binary<a class="headerlink" href="#binary" title="Permanent link">&para;</a></h2>
<ul>
<li>Stop the running instance of listmonk.</li>
<li>Download the <a href="https://github.com/knadh/listmonk/releases">latest release</a> and extract the listmonk binary and overwrite the previous version.</li>
<li><code>./listmonk --upgrade</code> to upgrade an existing database schema. Upgrades are idempotent and running them multiple times have no side effects.</li>
<li>Run <code>./listmonk</code> again.</li>
</ul>
<p>If you installed listmonk as a service, you will need to stop it before overwriting the binary. Something like <code>sudo systemctl stop listmonk</code> or <code>sudo service listmonk stop</code> should work. Then overwrite the binary with the new version, then run <code>./listmonk --upgrade, and</code>start` it back with the same commands.</p>
<p>If it's not running as a service, <code>pkill -9 listmonk</code> will stop the listmonk process.</p>
<h2 id="docker">Docker<a class="headerlink" href="#docker" title="Permanent link">&para;</a></h2>
<p><strong>Important:</strong> The following instructions are for the new <a href="https://github.com/knadh/listmonk/blob/master/docker-compose.yml">docker-compose.yml</a> file.</p>
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>compose<span class="w"> </span>down<span class="w"> </span>app
docker<span class="w"> </span>compose<span class="w"> </span>pull
docker<span class="w"> </span>compose<span class="w"> </span>up<span class="w"> </span>app<span class="w"> </span>-d
</code></pre></div>
<p>If you are using an older docker-compose.yml file, you have to run the <code>--upgrade</code> step manually.</p>
<div class="highlight"><pre><span></span><code>docker-compose<span class="w"> </span>down
docker-compose<span class="w"> </span>pull<span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span>docker-compose<span class="w"> </span>run<span class="w"> </span>--rm<span class="w"> </span>app<span class="w"> </span>./listmonk<span class="w"> </span>--upgrade
docker-compose<span class="w"> </span>up<span class="w"> </span>-d<span class="w"> </span>app<span class="w"> </span>db
</code></pre></div>
<h2 id="railway">Railway<a class="headerlink" href="#railway" title="Permanent link">&para;</a></h2>
<ul>
<li>Head to your dashboard, and select your Listmonk project.</li>
<li>Select the GitHub deployment service.</li>
<li>In the Deployment tab, head to the latest deployment, click on the three vertical dots to the right, and select "Redeploy".</li>
</ul>
<p><img alt="Railway Redeploy option" src="https://user-images.githubusercontent.com/55474996/226517149-6dc512d5-f862-46f7-a57d-5e55b781ff53.png" /></p>
<h2 id="downgrade">Downgrade<a class="headerlink" href="#downgrade" title="Permanent link">&para;</a></h2>
<p>To restore a previous version, you have to restore the DB for that particular version. DBs that have been upgraded with a particular version shouldn't be used with older versions. There may be DB changes that a new version brings that are incompatible with previous versions.</p>
<p><strong>General steps:</strong></p>
<ol>
<li>Stop listmonk.</li>
<li>Restore your pre-upgrade database.</li>
<li>If you're using <code>docker compose</code>, edit <code>docker-compose.yml</code> and change <code>listmonk:latest</code> to <code>listmonk:v2.4.0</code> <em>(for example)</em>.</li>
<li>Restart.</li>
</ol>
<p><strong>Example with docker:</strong></p>
<ol>
<li>Stop listmonk (app):
<div class="highlight"><pre><span></span><code>sudo docker stop listmonk_app
</code></pre></div></li>
<li>Restore your pre-upgrade db (required) <em>(be careful, this will wipe your existing DB)</em>:
<div class="highlight"><pre><span></span><code>psql -h 127.0.0.1 -p 9432 -U listmonk
drop schema public cascade;
create schema public;
\q
psql -h 127.0.0.1 -p 9432 -U listmonk -W listmonk &lt; listmonk-preupgrade-db.sql
</code></pre></div></li>
<li>Edit the <code>docker-compose.yml</code>:
<div class="highlight"><pre><span></span><code>x-app-defaults: &amp;app-defaults
restart: unless-stopped
image: listmonk/listmonk:v2.4.0
</code></pre></div></li>
<li>Restart:
<code>sudo docker compose up -d app db nginx certbot</code></li>
</ol>
<h2 id="upgrading-to-v4xx">Upgrading to v4.x.x<a class="headerlink" href="#upgrading-to-v4xx" title="Permanent link">&para;</a></h2>
<p>v4 is a major upgrade from prior versions with significant changes to certain important features and behaviour. It is the first version to have multi-user support and full fledged user management. Prior versions only had a simple BasicAuth for both admin login (browser prompt) and API calls, with the username and password defined in the TOML configuration file.</p>
<p>It is safe to upgrade an older installation with <code>--upgrade</code>, but there are a few important things to keep in mind. The upgrade automatically imports the <code>admin_username</code> and <code>admin_password</code> defined in the TOML configuration into the new user management system.</p>
<ol>
<li>
<p><strong>New login UI</strong>: Once you upgrade an older installation, the admin dashboard will no longer show the native browser prompt for login. Instead, a new login UI rendered by listmonk is displayed at the URI <code>/admin/login</code>.</p>
</li>
<li>
<p><strong>API credentials</strong>: If you are using APIs to interact with listmonk, after logging in, go to Settings -&gt; Users and create a new API user with the necessary permissions. Change existing API integrations to use these credentials instead of the old username and password defined in the legacy TOML configuration file or environment variables.</p>
</li>
<li>
<p><strong>Credentials in TOML file or old environment variables</strong>: The admin dashboard shows a warning until the <code>admin_username</code> and <code>admin_password</code> fields are removed from the configuration file or old environment variables. In v4.x.x, these are irrelevant as user credentials are stored in the database and managed from the admin UI. IMPORTANT: if you are using APIs to interact with listmonk, follow the previous step before removing the legacy credentials.</p>
</li>
</ol>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
CC BY-SA 4.0
</div>
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "..", "features": ["navigation.indexes", "navigation.sections", "content.code.copy"], "search": "../assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../assets/javascripts/bundle.92b07e13.min.js"></script>
</body>
</html>