Full Guide to Migrating SonarQube (Docker-based) from Cloud to On-Premise

What You'll Learn

  • What is SonarQube and why self-host it?

  • How to use Docker Compose to deploy it

  • How to persist data using volumes

  • How to migrate existing data (including backups)

  • Common gotchas and troubleshooting

Prerequisites

  • Access to source server (OpenStack) and target server (On-Premise)

  • Docker and Docker Compose installed on both

  • Sufficient disk space on both servers

  • SonarQube running in Docker (preferably using docker-compose)

  • SSH access between machines or the ability to transfer .tar.gz files

What is SonarQube?

SonarQube is a code quality and security tool that analyzes your source code to detect bugs, vulnerabilities, and code smells. It helps maintain clean, secure, and maintainable code.

📝 You can use SonarCloud (hosted) or self-host SonarQube for more control and data privacy.

Step 1: Take a Complete Backup from Source

A. Stop the running containers to ensure data consistency:

docker compose -f sonar.yml down

B. Create a tarball of Docker volumes (including PostgreSQL and SonarQube data):

cd /var/lib/docker/volumes/
tar -czvf sonar_backup.tar.gz \
  sonarqube_setup_sonarqube_data \
  sonarqube_setup_sonarqube_conf \
  sonarqube_setup_sonarqube_logs \
  sonarqube_setup_sonarqube_extensions \
  sonarqube_setup_sonarqube_bundled-plugins \
  sonarqube_setup_postgresql_data

Step 2: Transfer Backup to the Target Machine

Use scp or rsync to transfer the tarball:

scp sonar_backup.tar.gz user@<on-prem-ip>:/home/user/

Step 3: Restore Volumes on Target Server

A. Extract volumes

cd /var/lib/docker/volumes/
sudo tar -xzvf /home/user/sonar_backup.tar.gz

B. Set correct permissions

# For SonarQube and PostgreSQL volumes
sudo chown -R 1000:1000 /var/lib/docker/volumes/sonarqube_*

Tip: UID 1000 is the default user ID inside both SonarQube and PostgreSQL containers.

Step 4: Docker Compose File

Use the same sonar.yml or create a new one like this:

version: "3"

services:
  sonarqube:
    image: sonarqube:lts-community
    ports:
      - "9000:9000"
      - "9092:9092"
    depends_on:
      - db
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar
    volumes:
      - sonarqube_conf:/opt/sonarqube/conf
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_bundled-plugins:/opt/sonarqube/lib/bundled-plugins
    networks:
      sonar_network:
  db:
    image: postgres:10
    ports:
      - "5432:5432"
    command: postgres -c 'max_connections=300'
    volumes:
      - postgresql:/var/lib/postgresql
      - postgresql_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: sonar
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
    networks:
      sonar_network:
    restart: unless-stopped
volumes:
  sonarqube_conf:
  sonarqube_data:
  sonarqube_logs:
  sonarqube_extensions:
  sonarqube_bundled-plugins:
  postgresql:
  postgresql_data:
networks:
  sonar_network:

What’s Going On Here?

  • Postgres service: Stores SonarQube metadata

  • SonarQube service: The main app

  • Volumes: Help persist data across container restarts (super important for real-world usage)

  • restart: unless-stopped: Ensures your containers restart automatically if the server reboots

Step 5: Start Services

docker compose -f sonar.yml up -d

Step 6: Handle Maintenance Mode

If you see:

"SonarQube is under maintenance"

It means a database upgrade is required.

Fix:

Open in browser:

http://<your-ip>:9000/setup

Click “Upgrade”. After a successful migration, you’ll be redirected to the login screen.


Final Checks

  • Login with admin account

  • Projects visible

  • Plugins installed

  • Analysis history preserved


Common Troubleshooting

ProblemFix
invalid command \N in SQL restoreYou used COPY format SQL dump — prefer pg_dump with SQL format
Admin password lockedReset via DB UPDATE or recreate user using gen_random_uuid()
SonarQube not startingCheck vm.max_map_count and set to 262144
"Under Maintenance"Complete /setup page once
Elasticsearch failedEnsure memory is sufficient and use correct sysctl values

Production Notes

  • Use --volumes-from or NFS mounts for persistent storage in future

  • Automate daily DB + volume backup with cron + tar

  • Prefer pg_dump for full DB-level backups

  • Ensure volume permission mapping if using non-root Docker host user


Learnings & Conclusion

Migrating SonarQube with Docker volumes is a clean and reliable strategy if handled carefully — particularly with:

  • Volume structure

  • Permissions

  • Database version compatibility

  • And upgrade flows post-restore

You now have an exact clone of your old setup running on your on-premise server — fully migrated and production ready.


Credits & Tools Used


Want to talk about this?

I'm open to collaboration & feedback!
Connect with me on LinkedIn or drop a ⭐ on this guide if it helped you!

0
Subscribe to my newsletter

Read articles from Krishank Kaushik directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Krishank Kaushik
Krishank Kaushik