<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Soluce Technologies</title>
    <description>The latest articles on DEV Community by Soluce Technologies (@soluce_technologies).</description>
    <link>https://dev.to/soluce_technologies</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3684374%2Fd44fdb5c-4623-40ab-a72c-0307fabd47de.jpg</url>
      <title>DEV Community: Soluce Technologies</title>
      <link>https://dev.to/soluce_technologies</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/soluce_technologies"/>
    <language>en</language>
    <item>
      <title>Self-Hosting Portabase: A Comprehensive Guide to Effortless Database Backup and Restore</title>
      <dc:creator>Soluce Technologies</dc:creator>
      <pubDate>Mon, 29 Dec 2025 13:49:02 +0000</pubDate>
      <link>https://dev.to/soluce_technologies/self-hosting-portabase-a-comprehensive-guide-to-effortless-database-backup-and-restore-4e5b</link>
      <guid>https://dev.to/soluce_technologies/self-hosting-portabase-a-comprehensive-guide-to-effortless-database-backup-and-restore-4e5b</guid>
      <description>&lt;p&gt;&lt;em&gt;An open-source, agent-based backup and restore platform for self-hosted and decentralized infrastructure. Deploy it yourself for encrypted, automated backups across PostgreSQL, MySQL, MariaDB, MongoDB, SQLite, Redis, Valkey, Firebird, and MSSQL.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo video:&lt;/strong&gt; &lt;a href="https://youtu.be/1tNDvo0AaEE" rel="noopener noreferrer"&gt;https://youtu.be/1tNDvo0AaEE&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In database operations, recoverability is non-negotiable. Unplanned data loss translates directly into downtime, missed RPOs, and, depending on your sector, compliance exposure. Outsourcing backups to a managed third party often means handing over credentials, accepting opaque retention, and trading away network isolation.&lt;/p&gt;

&lt;p&gt;Portabase takes the opposite stance: a free, open-source (Apache-2.0), self-hosted control plane that orchestrates lightweight agents deployed next to your databases. The agents execute encrypted dumps and ship them to the storage backends &lt;em&gt;you&lt;/em&gt; control, without ever exposing the databases to inbound traffic. The stack is built on Next.js for the dashboard, a Rust/Tokio agent for execution, Better Auth, Drizzle ORM, and Docker for packaging.&lt;/p&gt;

&lt;p&gt;This guide walks through a from-scratch self-hosted deployment: dashboard, agent, database declaration, and first backup. Prerequisites are minimal: Docker and a tolerance for YAML.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed since the early builds
&lt;/h2&gt;

&lt;p&gt;If you followed an earlier version of this guide, note three breaking changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The agent was rewritten in Rust.&lt;/strong&gt; It is no longer a Python/Celery worker. The rewrite (repo: &lt;code&gt;portabase/agent-rust&lt;/code&gt;) eliminates an entire class of runtime errors, shrinks the resource footprint, and is the basis of the "secure-by-design" claim. Backups are now encrypted with &lt;strong&gt;AES-GCM&lt;/strong&gt; for confidentiality and integrity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The images moved namespaces.&lt;/strong&gt; Use &lt;code&gt;portabase/portabase&lt;/code&gt; (dashboard) and &lt;code&gt;portabase/agent&lt;/code&gt; (agent). The old &lt;code&gt;solucetechnologies/*&lt;/code&gt; images are deprecated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;There is now a CLI installer&lt;/strong&gt; that scaffolds compose files, generates secrets, and manages the container lifecycle. It is the recommended path.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why self-host Portabase
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isolation by default.&lt;/strong&gt; Databases stay inside their private networks. The control plane never dials into your environments; agents poll &lt;em&gt;outbound&lt;/em&gt; to the server. No inbound ports, smaller attack surface, zero-trust-friendly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No lock-in, no fees.&lt;/strong&gt; Apache-2.0, fully auditable codebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-backend storage.&lt;/strong&gt; Local disk, any S3-compatible target (AWS S3, MinIO, RustFS), Google Drive, and Google Cloud Storage. Azure Blob Storage is on the roadmap. You can fan a single backup out to &lt;strong&gt;multiple destinations simultaneously&lt;/strong&gt; for redundancy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real retention strategies.&lt;/strong&gt; Retention by count, retention by time, and Grandfather-Father-Son (GFS) rotation, not just a &lt;code&gt;find -mtime&lt;/code&gt; cron.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team-ready.&lt;/strong&gt; Workspaces, projects, and role-based access control (member / admin / owner) at both system and organization scope.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Supported databases
&lt;/h2&gt;

&lt;p&gt;All of the following are stable and tested in production:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Engine&lt;/th&gt;
&lt;th&gt;Tested versions&lt;/th&gt;
&lt;th&gt;Restore&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;12-18&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;5.7, 8, 9&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MariaDB&lt;/td&gt;
&lt;td&gt;10, 11&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MongoDB&lt;/td&gt;
&lt;td&gt;4-8&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;3.x&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firebird&lt;/td&gt;
&lt;td&gt;3.0, 4.0, 5.0&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MSSQL Server&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;2.8+&lt;/td&gt;
&lt;td&gt;No (backup only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Valkey&lt;/td&gt;
&lt;td&gt;7.2+&lt;/td&gt;
&lt;td&gt;No (backup only)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker &amp;amp; Docker Compose&lt;/strong&gt; (engine 20+).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A host&lt;/strong&gt; running Linux/macOS/Windows with ≥ 2 GB RAM and ≥ 10 GB free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basic YAML&lt;/strong&gt; literacy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database credentials&lt;/strong&gt; with dump/read permissions for whatever you intend to back up.&lt;/li&gt;
&lt;li&gt;Behind Traefik or Nginx? See the reverse-proxy guide: &lt;a href="https://portabase.io/docs/dashboard/installation/reverse-proxy" rel="noopener noreferrer"&gt;https://portabase.io/docs/dashboard/installation/reverse-proxy&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Architecture in one paragraph
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;central server&lt;/strong&gt; is the control plane: web UI, agent registry, backup configuration, restore triggers, storage and notification integrations. The &lt;strong&gt;agent&lt;/strong&gt; sits next to your databases and does the actual work. The server never contacts the agent; the agent periodically polls the server (default every 5 s, &lt;code&gt;POLLING&lt;/code&gt;). That single design decision is what removes the need for inbound firewall rules and contains the blast radius if the control plane is ever compromised.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Deploy the dashboard
&lt;/h2&gt;

&lt;p&gt;You have four install paths: CLI (recommended), &lt;code&gt;docker run&lt;/code&gt; (quick test), Docker Compose (production/GitOps), and a Kubernetes Helm chart. Both the CLI and the manual route are below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option A: CLI (recommended)
&lt;/h3&gt;

&lt;p&gt;Install the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://portabase.io/install | bash
portabase &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scaffold and start the dashboard in one shot. The CLI downloads the templates, generates &lt;code&gt;PROJECT_SECRET&lt;/code&gt;, wires up the internal PostgreSQL database, and launches the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portabase dashboard my-dashboard &lt;span class="nt"&gt;--port&lt;/span&gt; 8887 &lt;span class="nt"&gt;--start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you skipped &lt;code&gt;--start&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portabase start my-dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;code&gt;http://localhost:8887&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option B: Docker Compose (manual)
&lt;/h3&gt;

&lt;p&gt;Create a working directory and a &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;portabase-dashboard&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;portabase-app-prod&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;portabase/portabase:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;TZ&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Europe/Paris"&lt;/span&gt;   &lt;span class="c1"&gt;# Adjust to your timezone&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8887:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;portabase-data:/data&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-f&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://localhost/api/health"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;

  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;portabase-pg&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:17-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5433:5432"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres-data:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=${POSTGRES_DB}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=${POSTGRES_USER}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${POSTGRES_USER}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${POSTGRES_DB}"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;portabase-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This spins up the &lt;strong&gt;dashboard&lt;/strong&gt; on port 8887 and a &lt;strong&gt;PostgreSQL&lt;/strong&gt; instance for Portabase's own metadata. To be explicit: this Postgres holds Portabase's internal state, &lt;em&gt;not&lt;/em&gt; your backups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment configuration (&lt;code&gt;.env&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The current &lt;code&gt;.env&lt;/code&gt; is deliberately minimal. Storage backends, notification channels, and authentication (OAuth2 / OIDC) are configured &lt;strong&gt;in the dashboard UI&lt;/strong&gt;, not via environment variables, so the sprawling SMTP/OAuth/S3 blocks from older guides are gone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# --- App configuration ---
PROJECT_URL=http://localhost:8887

# Used to encrypt communication with agents. Generate a strong one:
#   openssl rand -hex 32
PROJECT_SECRET=change_me_please_generate_a_secure_hex_token

# --- Internal metadata database ---
POSTGRES_USER=portabase
POSTGRES_PASSWORD=changeme   # change this
POSTGRES_HOST=db
POSTGRES_PORT=5432
POSTGRES_DB=portabase

DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?schema=public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;PROJECT_SECRET&lt;/code&gt; is non-optional: it secures the agent ↔ server channel. Don't ship a placeholder to production.&lt;/p&gt;

&lt;p&gt;Launch and tail the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
docker compose logs &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The health check gates the app on the database, so startup is ordered. Once it's up, hit &lt;code&gt;http://localhost:8887&lt;/code&gt; and register. The first account gets admin in the default workspace.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt; users can install straight from the OCI registry:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;portabase oci://ghcr.io/portabase/charts/portabase &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; portabase &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; project.secret&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 32&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 2: Deploy an agent
&lt;/h2&gt;

&lt;p&gt;The agent is the Rust connector that runs near your databases. Install one on each host that owns databases you want backed up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option A: CLI
&lt;/h3&gt;

&lt;p&gt;On the database host, grab an &lt;strong&gt;Edge Key&lt;/strong&gt; from the dashboard (Agents → add a new agent), then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portabase agent my-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The wizard asks for the Edge Key and offers to add databases immediately, either by spinning up a fresh local PostgreSQL/MariaDB container, or by pointing at an existing/managed instance (host, port, credentials).&lt;/p&gt;

&lt;h3&gt;
  
  
  Option B: Docker Compose
&lt;/h3&gt;

&lt;p&gt;First create the external network the agent expects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create portabase_network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then scaffold the files. The config file must exist before first start, even if empty:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;portabase-agent &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;portabase-agent
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"databases": []}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; databases.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;portabase-agent&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;portabase-agent&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;portabase/agent:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./databases.json:/config/config.json&lt;/span&gt;   &lt;span class="c1"&gt;# mount your DB config&lt;/span&gt;
    &lt;span class="na"&gt;extra_hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost:host-gateway"&lt;/span&gt;               &lt;span class="c1"&gt;# lets the agent reach the host's localhost&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;TZ&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Europe/Paris"&lt;/span&gt;
      &lt;span class="na"&gt;LOG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;info&lt;/span&gt;
      &lt;span class="na"&gt;POLLING&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;APP_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
      &lt;span class="na"&gt;DATA_PATH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/data"&lt;/span&gt;
      &lt;span class="c1"&gt;# DATABASES_CONFIG_FILE: "config.toml"   # uncomment to use TOML instead&lt;/span&gt;
      &lt;span class="na"&gt;EDGE_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${EDGE_KEY}"&lt;/span&gt;                   &lt;span class="c1"&gt;# from the dashboard&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;portabase&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;portabase&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;portabase_network&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details that trip people up: the config file mounts to &lt;strong&gt;&lt;code&gt;/config/config.json&lt;/code&gt;&lt;/strong&gt; (not the old &lt;code&gt;/app/src/data/...&lt;/code&gt; path), and &lt;code&gt;extra_hosts&lt;/code&gt; is what lets the containerized agent reach databases bound to the host's &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Agent environment reference:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EDGE_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unique agent key from the dashboard&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Required&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TZ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Timezone (e.g. &lt;code&gt;UTC&lt;/code&gt;, &lt;code&gt;Europe/Paris&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UTC&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POLLING&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Poll frequency in seconds&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APP_ENV&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;production&lt;/code&gt; / &lt;code&gt;staging&lt;/code&gt; / &lt;code&gt;development&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;production&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DATA_PATH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Internal data path in the container&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/data&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LOG&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Log level (&lt;code&gt;info&lt;/code&gt;, &lt;code&gt;debug&lt;/code&gt;, …)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;info&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Declare your databases (&lt;code&gt;databases.json&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Mount a config file describing each connection. JSON is the default; TOML is supported and more readable. Each entry needs a &lt;strong&gt;unique UUID v4&lt;/strong&gt; in &lt;code&gt;generated_id&lt;/code&gt;. This is how the dashboard keeps a database's backup history stable even if you rename it. Generate one with &lt;code&gt;uuidgen&lt;/code&gt; (Linux/macOS) or any UUID v4 tool. &lt;strong&gt;Do not invent a random string.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"databases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PROD - api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"database"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prod_api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgresql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin_prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"super_secure_password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generated_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"550e8400-e29b-41d4-a716-446655440000"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DEV - site"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"database"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mariadb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.50"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3306&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"root"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dev_password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generated_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123e4567-e89b-12d3-a456-426614174000"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TOML equivalent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[[databases]]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"PROD - api"&lt;/span&gt;
&lt;span class="py"&gt;database&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"prod_api"&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"postgresql"&lt;/span&gt;
&lt;span class="py"&gt;host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"localhost"&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;
&lt;span class="py"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"admin_prod"&lt;/span&gt;
&lt;span class="py"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"super_secure_password"&lt;/span&gt;
&lt;span class="py"&gt;generated_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"550e8400-e29b-41d4-a716-446655440000"&lt;/span&gt;

&lt;span class="nn"&gt;[[databases]]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DEV - site"&lt;/span&gt;
&lt;span class="py"&gt;database&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"mariadb"&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"mysql"&lt;/span&gt;
&lt;span class="py"&gt;host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"192.168.1.50"&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3306&lt;/span&gt;
&lt;span class="py"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"root"&lt;/span&gt;
&lt;span class="py"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dev_password"&lt;/span&gt;
&lt;span class="py"&gt;generated_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"123e4567-e89b-12d3-a456-426614174000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Field notes: &lt;code&gt;type&lt;/code&gt; accepts &lt;code&gt;postgresql&lt;/code&gt;, &lt;code&gt;mysql&lt;/code&gt;, &lt;code&gt;mariadb&lt;/code&gt; (use &lt;code&gt;mysql&lt;/code&gt; for MariaDB), &lt;code&gt;sqlite&lt;/code&gt;, etc. After any manual edit, restart the agent so it reloads: &lt;code&gt;docker compose restart app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also let the CLI manage this file safely: &lt;code&gt;portabase db add &amp;lt;agent-path&amp;gt;&lt;/code&gt; validates syntax and generates the UUID for you; &lt;code&gt;portabase db list&lt;/code&gt; shows what's configured.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bring it online
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;   &lt;span class="c"&gt;# or: portabase start my-agent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the dashboard, the agent should register and flip to &lt;strong&gt;online&lt;/strong&gt; within a few poll cycles. If it doesn't, check &lt;code&gt;portabase logs my-agent&lt;/code&gt; for the "Ping server" line.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Configure backups and run the first one
&lt;/h2&gt;

&lt;p&gt;With server and agent connected:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set up workspaces and projects.&lt;/strong&gt; Organize databases, storage backends, and notification channels by organization and project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define a backup policy.&lt;/strong&gt; Cron-based schedule (or manual trigger) plus a retention strategy: by count, by time, or GFS rotation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick storage.&lt;/strong&gt; Local for a quick start; S3-compatible, Google Drive, or Google Cloud Storage for durability. Target several at once for redundancy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wire notifications.&lt;/strong&gt; Email, Slack, Discord, Telegram, Ntfy, Gotify, MS Teams, Pushover, or generic webhooks, with per-database alert rules for success/failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save and trigger.&lt;/strong&gt; Portabase validates the config and kicks off the first run. Monitor jobs, download dumps, or restore with one click.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Where the project is
&lt;/h2&gt;

&lt;p&gt;Since stepping up communication in late 2025 across Reddit, Medium, Dev.to, and Hacker News, Portabase has crossed &lt;strong&gt;1,100+ GitHub stars&lt;/strong&gt; with a growing stream of user-reported issues. Real adoption, not vanity metrics. It's already referenced on the MariaDB EcoHub and is in production internally and at several companies.&lt;/p&gt;

&lt;p&gt;On the near-term roadmap: extended PITR support via a universal connector, additional storage backends (Google Cloud Storage shipped; Azure Blob, FTP/SFTP planned), a RESTful API and an &lt;strong&gt;MCP server&lt;/strong&gt; for standardized automation, and a hosted cloud edition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Self-hosting Portabase turns backups from a fragile pile of cron scripts into a managed, observable pipeline you fully own, typically stood up in under 30 minutes. Encrypted, agent-isolated, multi-engine, and Apache-2.0.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://portabase.io/docs" rel="noopener noreferrer"&gt;https://portabase.io/docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard:&lt;/strong&gt; &lt;a href="https://github.com/portabase/portabase" rel="noopener noreferrer"&gt;https://github.com/portabase/portabase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust agent:&lt;/strong&gt; &lt;a href="https://github.com/portabase/agent" rel="noopener noreferrer"&gt;https://github.com/portabase/agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI:&lt;/strong&gt; &lt;a href="https://github.com/portabase/cli" rel="noopener noreferrer"&gt;https://github.com/portabase/cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discord:&lt;/strong&gt; &lt;a href="https://discord.gg/Wgv7xZ8fWJ" rel="noopener noreferrer"&gt;https://discord.gg/Wgv7xZ8fWJ&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Star the repos, deploy it, and report back: which database are you backing up first?&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>docker</category>
      <category>database</category>
    </item>
  </channel>
</rss>
