synapse/develop/usage/administration/backups.html

313 lines
30 KiB
HTML
Raw Normal View History

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Backups - Synapse</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="../../favicon.svg">
<link rel="shortcut icon" href="../../favicon.png">
<link rel="stylesheet" href="../../css/variables.css">
<link rel="stylesheet" href="../../css/general.css">
<link rel="stylesheet" href="../../css/chrome.css">
<link rel="stylesheet" href="../../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../../highlight.css">
<link rel="stylesheet" href="../../tomorrow-night.css">
<link rel="stylesheet" href="../../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../../docs/website_files/table-of-contents.css">
<link rel="stylesheet" href="../../docs/website_files/remove-nav-buttons.css">
<link rel="stylesheet" href="../../docs/website_files/indent-section-headers.css">
<link rel="stylesheet" href="../../docs/website_files/version-picker.css">
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "../../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><li class="part-title">Introduction</li><li class="chapter-item expanded "><a href="../../welcome_and_overview.html">Welcome and Overview</a></li><li class="chapter-item expanded affix "><li class="part-title">Setup</li><li class="chapter-item expanded "><a href="../../setup/installation.html">Installation</a></li><li class="chapter-item expanded "><a href="../../postgres.html">Using Postgres</a></li><li class="chapter-item expanded "><a href="../../reverse_proxy.html">Configuring a Reverse Proxy</a></li><li class="chapter-item expanded "><a href="../../setup/forward_proxy.html">Configuring a Forward/Outbound Proxy</a></li><li class="chapter-item expanded "><a href="../../turn-howto.html">Configuring a Turn Server</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../setup/turn/coturn.html">coturn TURN server</a></li><li class="chapter-item expanded "><a href="../../setup/turn/eturnal.html">eturnal TURN server</a></li></ol></li><li class="chapter-item expanded "><a href="../../delegate.html">Delegation</a></li><li class="chapter-item expanded affix "><li class="part-title">Upgrading</li><li class="chapter-item expanded "><a href="../../upgrade.html">Upgrading between Synapse Versions</a></li><li class="chapter-item expanded affix "><li class="part-title">Usage</li><li class="chapter-item expanded "><a href="../../federate.html">Federation</a></li><li class="chapter-item expanded "><a href="../../usage/configuration/index.html">Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../usage/configuration/config_documentation.html">Configuration Manual</a></li><li class="chapter-item expanded "><a href="../../usage/configuration/homeserver_sample_config.html">Homeserver Sample Config File</a></li><li class="chapter-item expanded "><a href="../../usage/configuration/logging_sample_config.html">Logging Sample Config File</a></li><li class="chapter-item expanded "><a href="../../structured_logging.html">Structured Logging</a></li><li class="chapter-item expanded "><a href="../../templates.html">Templates</a></li><li class="chapter-item expanded "><a href="../../usage/configuration/user_authentication/index.html">User Authentication</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../usage/configuration/user_authentication/single_sign_on/index.html">Single-Sign On</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../openid.html">OpenID Connect</a></li><li class="chapter-item expanded "><a href="../../usage/configuration/user_authentication/single_sign_on/saml.html">SAML</a></li><li class="chapter-item expanded "><a href="../../usage/configuration/user_authentication/single_sign_on/cas.html">CAS</a></li><li class="chapter-item expanded "><a href="../../sso_mapping_providers.html">SSO Mapping Providers</a></li></ol></li><li class="chapter-item expanded "><a href="../../password_auth_providers.html">Password Auth Providers</a></li><li class="chapter-item expanded "><a href="../../jwt.html">JSON Web Tokens</a></li><li class="chapter-item expanded "><a href="../../usage/configuration/user_authentication/refresh_tokens.html">Refresh Tokens</a></li></ol></li><li class="chapter-item expanded "><a href="../../CAPTCHA_SETUP.html">Registration Captcha</a></li><li class="chapter-item expanded "><a href="../../application_services.html">Application Services</a></li><li class="chapter-item expanded "><a href="../../server_notices.html">Server Notices</a></li><li class="chapter-item expanded "><a href="../../consent_tracking.html">Consent Tracking</a></li><li class="chapter-item expanded "><a href="../../user_directory.html">User Directory</a></li><li class="chapter-item expanded "><a href="../../message_retention_policies.html">Message Retention Policies</a></li><li class="chapter-item expanded "><a href="../../modules/index.html">Pluggable Modules</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../modules/writ
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
<div class="version-picker">
<div class="dropdown">
<div class="select">
<span></span>
<i class="fa fa-chevron-down"></i>
</div>
<input type="hidden" name="version">
<ul class="dropdown-menu">
<!-- Versions will be added dynamically in version-picker.js -->
</ul>
</div>
</div>
</div>
<h1 class="menu-title">Synapse</h1>
<div class="right-buttons">
<a href="../../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/element-hq/synapse" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/element-hq/synapse/edit/develop/docs/usage/administration/backups.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<!-- Page table of contents -->
<div class="sidetoc">
<nav class="pagetoc"></nav>
</div>
<h1 id="how-to-back-up-a-synapse-homeserver"><a class="header" href="#how-to-back-up-a-synapse-homeserver">How to back up a Synapse homeserver</a></h1>
<p>It is critical to maintain good backups of your server, to guard against
hardware failure as well as potential corruption due to bugs or administrator
error.</p>
<p>This page documents the things you will need to consider backing up as part of
a Synapse installation.</p>
<h2 id="configuration-files"><a class="header" href="#configuration-files">Configuration files</a></h2>
<p>Keep a copy of your configuration file (<code>homeserver.yaml</code>), as well as any
auxiliary config files it refers to such as the
<a href="../configuration/config_documentation.html#log_config"><code>log_config</code></a> file,
<a href="../configuration/config_documentation.html#app_service_config_files"><code>app_service_config_files</code></a>.
Often, all such config files will be kept in a single directory such as
<code>/etc/synapse</code>, which will make this easier.</p>
<h2 id="server-signing-key"><a class="header" href="#server-signing-key">Server signing key</a></h2>
<p>Your server has a <a href="../configuration/config_documentation.html#signing_key_path">signing
key</a> which it uses
to sign events and outgoing federation requests. It is easiest to back it up
with your configuration files, but an alternative is to have Synapse create a
new signing key if you have to restore.</p>
<p>If you do decide to replace the signing key, you should add the old <em>public</em>
key to
<a href="../configuration/config_documentation.html#old_signing_keys"><code>old_signing_keys</code></a>.</p>
<h2 id="database"><a class="header" href="#database">Database</a></h2>
<p>Synapse's support for SQLite is only suitable for testing purposes, so for the
purposes of this document, we'll assume you are using
<a href="../../postgres.html">PostgreSQL</a>.</p>
<p>A full discussion of backup strategies for PostgreSQL is out of scope for this
document; see the <a href="https://www.postgresql.org/docs/current/backup.html">PostgreSQL
documentation</a> for
detailed information.</p>
<h3 id="synapse-specfic-details"><a class="header" href="#synapse-specfic-details">Synapse-specfic details</a></h3>
<ul>
<li>
<p>Be very careful not to restore into a database that already has tables
present. At best, this will error; at worst, it will lead to subtle database
inconsistencies.</p>
</li>
<li>
<p>The <code>e2e_one_time_keys_json</code> table should <strong>not</strong> be backed up, or if it is
backed up, should be
<a href="https://www.postgresql.org/docs/current/sql-truncate.html"><code>TRUNCATE</code>d</a>
after restoring the database before Synapse is started.</p>
<p>[Background: restoring the database to an older backup can cause
used one-time-keys to be re-issued, causing subsequent <a href="https://github.com/element-hq/element-meta/issues/2155">message decryption
errors</a>. Clearing
all one-time-keys from the database ensures that this cannot happen, and
will prompt clients to generate and upload new one-time-keys.]</p>
</li>
</ul>
<h3 id="quick-and-easy-database-backup-and-restore"><a class="header" href="#quick-and-easy-database-backup-and-restore">Quick and easy database backup and restore</a></h3>
<p>Typically, the easiest solution is to use <code>pg_dump</code> to take a copy of the whole
database. We recommend <code>pg_dump</code>'s custom dump format, as it produces
significantly smaller backup files.</p>
<pre><code class="language-shell">sudo -u postgres pg_dump -Fc --exclude-table-data e2e_one_time_keys_json synapse &gt; synapse.dump
</code></pre>
<p>There is no need to stop Postgres or Synapse while <code>pg_dump</code> is running: it
will take a consistent snapshot of the databse.</p>
<p>To restore, you will need to recreate the database as described in <a href="../../postgres.html#set-up-database">Using
Postgres</a>,
then load the dump into it with <code>pg_restore</code>:</p>
<pre><code class="language-shell">sudo -u postgres createdb --encoding=UTF8 --locale=C --template=template0 --owner=synapse_user synapse
sudo -u postgres pg_restore -d synapse &lt; synapse.dump
</code></pre>
<p>(If you forgot to exclude <code>e2e_one_time_keys_json</code> during <code>pg_dump</code>, remember
to connect to the new database and <code>TRUNCATE e2e_one_time_keys_json;</code> before
starting Synapse.)</p>
<p>To reiterate: do <strong>not</strong> restore a dump over an existing database.</p>
<p>Again, if you plan to run your homeserver at any sort of production level, we
recommend studying the PostgreSQL documentation on backup options.</p>
<h2 id="media-store"><a class="header" href="#media-store">Media store</a></h2>
<p>Synapse keeps a copy of media uploaded by users, including avatars and message
attachments, in its <a href="../configuration/config_documentation.html#media-store">Media
store</a>.</p>
<p>It is a directory on the local disk, containing the following directories:</p>
<ul>
<li>
<p><code>local_content</code>: this is content uploaded by your local users. As a general
rule, you should back this up: it may represent the only copy of those
media files anywhere in the federation, and if they are lost, users will
see errors when viewing user or room avatars, and messages with attachments.</p>
</li>
<li>
<p><code>local_thumbnails</code>: &quot;thumbnails&quot; of images uploaded by your users. If
<a href="../configuration/config_documentation.html#dynamic_thumbnails"><code>dynamic_thumbnails</code></a>
is enabled, these will be regenerated if they are removed from the disk, and
there is therefore no need to back them up.</p>
<p>If <code>dynamic_thumbnails</code> is <em>not</em> enabled (the default): although this can
theoretically be regenerated from <code>local_content</code>, there is no tooling to do
so. We recommend that these are backed up too.</p>
</li>
<li>
<p><code>remote_content</code>: this is a cache of content that was uploaded by a user on
another server, and has since been requested by a user on your own server.</p>
<p>Typically there is no need to back up this directory: if a file in this directory
is removed, Synapse will attempt to fetch it again from the remote
server.</p>
</li>
<li>
<p><code>remote_thumbnails</code>: thumbnails of images uploaded by users on other
servers. As with <code>remote_content</code>, there is normally no need to back this
up.</p>
</li>
<li>
<p><code>url_cache</code>, <code>url_cache_thumbnails</code>: temporary caches of files downloaded
by the <a href="../../setup/installation.html#url-previews">URL previews</a> feature.
These do not need to be backed up.</p>
</li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../usage/administration/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../../usage/administration/admin_api/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../../usage/administration/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../../usage/administration/admin_api/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="../../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../../mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../../searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="../../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../../highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="../../book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
<script type="text/javascript" src="../../docs/website_files/table-of-contents.js"></script>
<script type="text/javascript" src="../../docs/website_files/version-picker.js"></script>
<script type="text/javascript" src="../../docs/website_files/version.js"></script>
</body>
</html>