Introduction
If you're currently hosting your database on another cloud provider and watching your monthly bills grow, migrating to Hetzner can dramatically reduce your costs while potentially improving performance. Many users report equivalent or better performance compared to much more expensive cloud options, especially for database workloads.
In this guide, I'll walk you through transferring your databases to Hetzner using DBConvert Streams — a powerful database migration platform designed to simplify moving data between different hosting environments and database types.
Prerequisites
Before you start, make sure you have:
- An account with DBConvert (free trial for 14 days)
- A Hetzner Cloud account
- Your source database credentials (e.g., AWS RDS, Google Cloud SQL, Azure DB)
- Basic familiarity with Linux commands
- SSH key added to your Hetzner Cloud account
Example terminology
- Server:
<10.0.0.1>
Step 1 - Create a Hetzner Cloud Server
First, let's create a Hetzner cloud server with Docker pre-installed.
For a step-by-step guide, see this getting started.
- For the image, choose the "Apps" tab and select "Docker CE"
- Select a server type based on your database needs:
- For development/small production databases: CPX21 (2 vCPU, 4GB RAM)
- For medium workloads: CPX31 (4 vCPU, 8GB RAM)
- For larger production databases: CPX41 (8 vCPU, 16GB RAM)
- Add your SSH key or create a new one
Note: The "CPX" line is recommended for database workloads as they offer NVMe SSD storage with higher I/O performance compared to the standard "CX" instances.
Step 2 - Set Up PostgreSQL on Hetzner
For simplicity in this tutorial, we'll deploy both DBConvert Streams and our target PostgreSQL database on the same server.
-
SSH into your new Hetzner server:
Replace
<10.0.0.1>
with the IP address of your cloud server.ssh root@<10.0.0.1>
-
Create directories for PostgreSQL data and configuration:
mkdir -p ~/pg-data ~/pg-conf
-
Run PostgreSQL in Docker:
docker run -d \ --name postgres \ -e POSTGRES_USER=pguser \ -e POSTGRES_PASSWORD=strongpassword \ -e POSTGRES_DB=mydb \ -v ~/pg-data:/var/lib/postgresql/data \ -p 5432:5432 \ postgres:16
Make sure to replace
strongpassword
with a secure password andmydb
with your desired database name. -
Verify PostgreSQL is running:
docker ps
You should see your PostgreSQL container running on port 5432.
Step 3 - Deploy DBConvert Streams
Now, let's install DBConvert Streams on the same server:
-
Download and install DBConvert Streams:
curl -fsSL https://dbconvert.nyc3.digitaloceanspaces.com/downloads/streams/latest/docker-install.sh | sh
Click here to view the output
root@example-server:~# curl -fsSL https://dbconvert.nyc3.digitaloceanspaces.com/downloads/streams/latest/docker-install.sh | sh Installing gum using binary installation... ┌──────────────────────────────────────────────────────────────┐ │ │ │ Welcome to DBConvert Streams Installation │ │ This wizard will guide you through the installation process. │ │ │ └──────────────────────────────────────────────────────────────┘ Checking latest available version... Latest version available: v1.3.0 ┌──────────────────────────────────────────┐ │ │ │ Installing DBConvert Streams │ │ Version: v1.3.0 │ │ Directory: /opt/dbconvert-streams-docker │ │ │ └──────────────────────────────────────────┘ Starting installation... Installing DBConvert Streams... Checking prerequisites... Downloading deployment files... Updating version information in .env file... [...] Self-signed certificate generated successfully! Private key: config/certs/private.key Certificate: config/certs/certificate.crt Setting up nginx configuration... Configuring nginx with HTTP only... Nginx configuration complete! Installation complete! DBConvert Streams Version Information Latest available version: Latest version: v1.3.0 Configured versions in .env file: streams: v1.3.0 stream-ui: v1.3.2 No DBConvert Streams services are currently running ┌──────────────────────────────────────────────────────────────────────────────────┐ │ │ │ Installation Complete! │ │ Your DBConvert Streams installation is ready. │ │ │ │ To start the services: │ │ 1. Change to the installation directory: │ │ cd /opt/dbconvert-streams-docker │ │ 2. Run the start script: │ │ For HTTP: ./start.sh │ │ For HTTPS: ./start.sh --secure │ │ │ │ You can switch between HTTP and HTTPS modes at any time using the --secure flag. │ │ │ └──────────────────────────────────────────────────────────────────────────────────┘
-
Navigate to the installation directory and start the services:
cd /opt/dbconvert-streams-docker/ ./start.sh
After the services start up, you'll see a message with your service URLs:
┌────────────────────────────────────────────────────────────────────┐ │ │ │ Service URLs │ │ │ │ • UI: http://<10.0.0.1> │ │ • API: http://<10.0.0.1>/api/ │ │ │ │ Setup complete! You can now access the services at the URLs above. │ │ │ └────────────────────────────────────────────────────────────────────┘
Step 4 - Obtain and Enter Your API Key
- Go to https://streams.dbconvert.com/account
- Sign in using your preferred authentication method
- Copy your API key from the account dashboard
- Return to your DBConvert Streams instance:
http://<10.0.0.1>
- Paste the API key in the provided field
DBConvert Streams offers a free trial that includes:
- 5GB of data transfer
- 14 days of unlimited access to all features
- No credit card required to start
Step 5 - Connect Your Source Database
Step 5.1 - Configure Source Database Access
Make sure DBConvert Streams can can access your source database.
This step is different, depending on your provider.
-
Google Cloud SQL MySQL
- In the Google Cloud Console, navigate to your Cloud SQL instance
- Go to the "Connections" tab
- Under "Networking," select "Add network"
- Add your Hetzner server's IP address
- Save your changes
Step 5.2 - Create the Source Connection
- Return to your DBConvert Streams instance:
http://<10.0.0.1>
- Click the quick action "Create Connection" in the dashboard
- Select your database type (e.g., MySQL)
- Enter your connection details:
- Name: Optional. Give your connection a descriptive name
- Server: Your source database IP/hostname
- Port: Database port (e.g., 3306 for MySQL)
- User ID: Your database username
- Password: Your database password
- Database: Source database name
- Click "Add"
- Test the connection
- Click "Update" to store the connection
Step 6 - Connect Your Hetzner PostgreSQL Database
- Return to the dashboard
- Click the quick action "Create Connection" in the dashboard
- Select "PostgreSQL"
- Enter the connection details:
- Host: Your Hetzner server IP
- Port: 5432
- Username: pguser
- Password: Your PostgreSQL password
- Database: mydb
- Click "Add"
- Test the connection
- Click "Update" to save the configuration
Step 7 - Configure Your Data Stream
-
Return to the dashboard
-
Click "Create New Stream"
-
Select your source connection and click "Next" in the top right
-
Choose tables to migrate
Select transfer mode:
- Convert/Migrate: For one-time migrations
- CDC/Stream: For continuous replication
Configure options:
- Data bundle size
- Index creation options
- Custom SQL queries (if needed)
When you're happy with your settings, click "Next" in the top right
-
Select your target Hetzner PostgreSQL connection and click "Save" in the top right
Step 8 - Start and Monitor the Transfer
- Click the "Start" button to begin
- Monitor the transfer through the dashboard:
- Track progress for each table
- Monitor data transfer rates
- View detailed logs
- Pause or stop if needed
Step 9 - Verify Your Data
-
Connect to your PostgreSQL database:
docker exec -it postgres psql -U pguser -d mydb
-
Run verification queries:
-- List all tables in the database \dt -- Get row counts for all tables SELECT schemaname as schema, relname as table_name, n_live_tup as row_count FROM pg_stat_user_tables ORDER BY n_live_tup DESC; -- Check table sizes including indexes SELECT table_schema, table_name, pg_size_pretty(pg_total_relation_size('"' || table_schema || '"."' || table_name || '"')) as total_size FROM information_schema.tables WHERE table_schema = 'public' ORDER BY pg_total_relation_size('"' || table_schema || '"."' || table_name || '"') DESC;
-
Compare these results with your source database to ensure:
- All tables are present
- Row counts match
- Data sizes are reasonable
- Primary keys and indexes are properly transferred
If the numbers don't match or you notice any discrepancies, you may need to investigate specific tables in more detail.
Step 10 - Set Up Database Backups
Hetzner Snapshots
- In Hetzner Cloud Console, select your server
- Click "Snapshots"
- Click "Create Snapshot"
See Snapshot prices at hetzner.com/cloud.
Conclusion
You've successfully migrated your database to Hetzner Cloud using DBConvert Streams. This setup provides you with:
- Significant cost savings compared to other cloud providers
- Full control over your database infrastructure
- Automated backups for data security
- High-performance NVMe storage
- Simple management through Docker containers
Remember to monitor your database performance and adjust server resources as needed. You can easily scale your Hetzner server up or down based on your workload requirements.