SonarQube 공식 ZIP과 릴리스 정보, 라이선스가 필요한 에디션의 유효 라이선스
CODE QUALITY PLATFORM
SonarQube 2026.1 LTA·PostgreSQL 연동
SonarQube 2026.1 LTA의 Linux·JDK 요구사항을 검증하고 전용 PostgreSQL 역할과 DB, 외부화한 자격증명, systemd 서비스와 루프백 프록시 경계를 구성해 안전하게 운영합니다.BEFORE YOU START
시작 전에 준비하세요
JDK 21·25 중 조직이 지원하는 최신 보안 패치
PostgreSQL 14~18 서버와 백업·복원 검증
루프백 9000을 TLS로 노출할 역방향 프록시와 복구 콘솔
권장 대상 H2 테스트 구성이 아닌 운영용 PostgreSQL과 SonarQube를 최소 권한·TLS 프록시 구조로 처음 연동하려는 플랫폼 운영자
FOLLOW THE RECIPE
8단계 구성·점검 레시피
지원 버전과 배치 구조 확정
이 가이드는 2026.1 LTA ZIP 설치를 기준으로 합니다. 운영 DB는 H2가 아닌 PostgreSQL 14~18을 사용하고, 규모가 크면 DB를 저지연 전용 호스트에 분리합니다.
cat /etc/os-release
uname -mjava -version
javac -versionpsql --versionnproc
free -h
df -hT / /var /opt- SonarQube 2026.1 LTA와 JDK 21 또는 25 조합을 공식 요구사항에서 확인했습니다.
- PostgreSQL이 14~18 범위이며 테스트용 H2를 운영에 사용하지 않습니다.
- DB·검색 데이터·로그의 백업과 복구 시간을 정했습니다.
JRE만 있거나 Java 17이면 2026.1 LTA 요구사항을 충족하지 않습니다. ZIP 설치 전 JDK와 DB 지원 범위를 먼저 맞춥니다.
Elasticsearch 호스트 한계와 기존 포트·DB 상태를 점검합니다.
Linux 한계·DB·포트 사전 점검
SonarQube 내장 Elasticsearch는 커널 map count, 파일 디스크립터, 프로세스 수와 쓰기 가능한 임시공간을 요구합니다. 기존 9000·9001 리슨과 PostgreSQL 연결도 변경 전에 기록합니다.
sysctl vm.max_map_count
sysctl fs.file-maxgrep SECCOMP /boot/config-$(uname -r)
findmnt /tmp
test -w /tmpsudo ss -lntup | grep -E ':(9000|9001)[[:space:]]'
systemctl --failed --no-pagersudo -u postgres psql -Atc 'SHOW server_version;'
sudo -u postgres psql -Atc 'SHOW listen_addresses;'sudo stat -c '%U %G %a %n' /opt/sonarqube/conf/sonar.properties /etc/systemd/system/sonarqube.service없다는 메시지는 신규 설치입니다. 파일 내용을 출력하지 않습니다.- vm.max_map_count가 524288 이상, fs.file-max가 131072 이상입니다.
- SonarQube 계정이 사용할 /tmp가 쓰기 가능합니다.
- 9000·9001 충돌과 기존 서비스 영향을 확인했습니다.
- PostgreSQL 백업과 저지연 연결 경로가 준비됐습니다.
한계가 부족한 상태에서 서비스를 반복 시작하면 원인을 가리는 재시작 루프만 늘어납니다. 먼저 공식 최소값과 systemd 한계를 적용합니다.
전용 계정·JDK·PostgreSQL 역할과 데이터베이스를 준비합니다.
전용 계정과 PostgreSQL DB·배포 파일 설치
SonarQube를 root로 실행하지 않습니다. PostgreSQL 역할 비밀번호는 createuser의 대화형 프롬프트에서만 입력하고 셸 인자·SQL 파일에 남기지 않습니다.
sudo useradd --system --home-dir /var/lib/sonarqube --create-home --shell /usr/sbin/nologin sonarqube계정이 이미 있으면 UID·홈·셸을 확인하고 다시 만들지 않습니다.sudo -u postgres createuser --no-superuser --no-createdb --no-createrole --pwprompt sonarqube비밀번호는 프롬프트에만 입력합니다. 역할이 이미 있으면 변경하지 말고 속성을 점검합니다.sudo -u postgres createdb --owner=sonarqube --encoding=UTF8 sonarqube기존 DB가 있으면 새로 만들지 말고 백업과 소유자를 검증합니다.sudo apt-get install unzip최소 Ubuntu 설치에도 unzip이 있다고 가정하지 않습니다. 설치 변경을 검토한 뒤 ZIP 무결성 검사보다 먼저 준비합니다.unzip -t sonarqube-<SONAR_VERSION>.zip공식 다운로드에서 받은 파일인지 릴리스 페이지와 별도로 대조합니다.sudo install -d -m 0755 -o root -g root /opt/sonarqube
sudo install -d -m 0750 -o sonarqube -g sonarqube /var/lib/sonarqube/data /var/lib/sonarqube/temp /var/log/sonarqube /etc/sonarqubesudo test -z "$(sudo find /opt/sonarqube -mindepth 1 -maxdepth 1 -print -quit)"신규 설치 분기에서만 성공해야 합니다. 기존 설치가 있으면 압축을 풀지 말고 업그레이드 절차로 전환합니다.sudo unzip -q sonarqube-<SONAR_VERSION>.zip -d /opt/sonarqube-staging압축 내부 최상위 디렉터리를 확인한 뒤 /opt/sonarqube에 배치하며 기존 경로를 덮어쓰지 않습니다.sudo test -d /opt/sonarqube-staging/sonarqube-<SONAR_VERSION>/lib
sudo find /opt/sonarqube-staging/sonarqube-<SONAR_VERSION> -mindepth 1 -maxdepth 1 -printf '%f\n'lib·conf·extensions 등 공식 배포 구조가 아니면 복사하지 않습니다.sudo cp --archive --no-clobber /opt/sonarqube-staging/sonarqube-<SONAR_VERSION>/. /opt/sonarqube/
sudo chown -R sonarqube:sonarqube /opt/sonarqube비어 있음을 확인한 신규 설치 경로에만 복사합니다. staging은 검증이 끝날 때까지 보존합니다.- sonarqube 계정은 로그인할 수 없고 root가 아닙니다.
- DB 역할은 superuser·createdb·createrole 권한이 없습니다.
- DB 비밀번호가 명령 이력·SQL 파일에 없습니다.
- 기존 설치 경로를 덮어쓰지 않았습니다.
createdb가 이미 존재한다고 실패하면 삭제·재생성하지 않습니다. 기존 DB의 소유자·버전·백업과 애플리케이션 사용 여부를 확인합니다.
커널 한계, JDBC 비밀 파일, sonar.properties와 systemd 유닛을 백업 후 구성합니다.
커널 한계·JDBC·systemd 구성
비밀번호는 root와 sonarqube만 읽는 환경 파일에 대화형으로 입력하고 sonar.properties에는 URL·사용자·루프백·데이터 경로만 둡니다. 설정과 유닛을 기존 파일 위에 저장하기 전 백업합니다.
sudo cp --archive --no-clobber /etc/sysctl.d/99-sonarqube.conf /etc/sysctl.d/99-sonarqube.conf.<BACKUP_SUFFIX>.bak기존 파일이 있을 때만 실행합니다.sonar_map_current="$(sysctl -n vm.max_map_count)"
sonar_file_current="$(sysctl -n fs.file-max)"
case "$sonar_map_current" in ''|*[!0-9]*) echo 'vm.max_map_count is not numeric' >&2; exit 1 ;; esac
case "$sonar_file_current" in ''|*[!0-9]*) echo 'fs.file-max is not numeric' >&2; exit 1 ;; esac
printf 'vm.max_map_count=%s\nfs.file-max=%s\n' "$sonar_map_current" "$sonar_file_current" | sudo tee /etc/sonarqube/sysctl.<BACKUP_SUFFIX>.previous >/dev/null || exit 1
sonar_map_target="$sonar_map_current"
sonar_file_target="$sonar_file_current"
if [ "$sonar_map_target" -lt 524288 ]; then sonar_map_target=524288; fi
if [ "$sonar_file_target" -lt 131072 ]; then sonar_file_target=131072; fi
printf 'vm.max_map_count=%s\nfs.file-max=%s\n' "$sonar_map_target" "$sonar_file_target" | sudo tee /etc/sysctl.d/99-sonarqube.conf >/dev/null || exit 1
sudo chown root:root /etc/sysctl.d/99-sonarqube.conf /etc/sonarqube/sysctl.<BACKUP_SUFFIX>.previous || exit 1
sudo chmod 0644 /etc/sysctl.d/99-sonarqube.conf || exit 1
sudo chmod 0600 /etc/sonarqube/sysctl.<BACKUP_SUFFIX>.previous || exit 1
unset sonar_map_current sonar_file_current sonar_map_target sonar_file_target각 값은 max(변경 전 현재값, 공식 최소값)으로 계산됩니다. 출력값을 직접 낮춰 적지 말고, 이 명령이 중간에 실패하면 다음 단계로 진행하지 않습니다.sudo cp --archive --no-clobber /opt/sonarqube/conf/sonar.properties /opt/sonarqube/conf/sonar.properties.<BACKUP_SUFFIX>.bak배치된 원본을 보존합니다.sudoedit /opt/sonarqube/conf/sonar.propertiessudo cp --archive --no-clobber /etc/sonarqube/sonarqube.env /etc/sonarqube/sonarqube.env.<BACKUP_SUFFIX>.bak기존 파일이 있을 때만 실행하고 백업도 root 외에는 읽지 못하게 유지합니다.sudoedit /etc/sonarqube/sonarqube.envSONAR_JDBC_PASSWORD 값을 대화형 편집기에 입력하고 화면 공유·클립보드 이력을 지웁니다.sudo chown root:sonarqube /etc/sonarqube/sonarqube.env
sudo chmod 640 /etc/sonarqube/sonarqube.envsudo cp --archive --no-clobber /etc/systemd/system/sonarqube.service /etc/systemd/system/sonarqube.service.<BACKUP_SUFFIX>.bak기존 파일이 있을 때만 실행합니다.sudoedit /etc/systemd/system/sonarqube.servicesonar.jdbc.username=sonarqube
sonar.jdbc.url=jdbc:postgresql://<DB_PRIVATE_HOST>:5432/sonarqube
sonar.web.host=127.0.0.1
sonar.web.port=9000
sonar.path.data=/var/lib/sonarqube/data
sonar.path.temp=/var/lib/sonarqube/temp
sonar.path.logs=/var/log/sonarqube[Unit]
Description=SonarQube Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=sonarqube
Group=sonarqube
EnvironmentFile=/etc/sonarqube/sonarqube.env
ExecStart=/usr/bin/java -Xms32m -Xmx32m -Djava.net.preferIPv4Stack=true -jar /opt/sonarqube/lib/sonar-application-<SONAR_BUILD>.jar
Restart=on-failure
SuccessExitStatus=143
LimitNOFILE=131072
LimitNPROC=8192
TimeoutStartSec=120
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target<SONAR_BUILD>는 실제 설치 파일명과 정확히 맞춥니다. Java 절대 경로도 command -v java 결과를 확인해 고정합니다.- 생성된 커널 값이 변경 전 값보다 작지 않고 공식 최소값 이상입니다.
- JDBC 비밀번호는 sonar.properties·명령 인자에 없습니다.
- 9000은 루프백에만 바인딩됩니다.
- 데이터·temp·로그가 버전별 설치 경로 밖에 있습니다.
- 기존 파일마다 고유 백업을 만들었습니다.
환경 파일도 평문 비밀 저장소이므로 파일 권한만으로 끝내지 않습니다. 가능한 환경에서는 비밀 관리 시스템으로 주입하고 초기 부팅 뒤 SonarQube의 민감 설정 암호화를 검토합니다.
구문과 권한을 검사한 뒤 sysctl과 서비스를 반영합니다.
설정 검증 후 서비스 시작
유닛·JDK·파일 권한과 PostgreSQL 연결을 서비스 계정 관점에서 확인한 뒤에만 시작합니다. 재시작을 반복하지 않고 첫 오류 로그를 보존합니다.
sudo sysctl -p /etc/sysctl.d/99-sonarqube.conf
sysctl vm.max_map_count
sysctl fs.file-max다른 제품의 sysctl 파일까지 다시 적용하는 sysctl --system은 사용하지 않습니다.sudo -u sonarqube test -r /opt/sonarqube/conf/sonar.properties
sudo -u sonarqube test -w /var/lib/sonarqube/data
sudo -u sonarqube test -w /var/lib/sonarqube/temp
sudo -u sonarqube test -w /var/log/sonarqubesudo systemd-analyze verify /etc/systemd/system/sonarqube.servicesudo systemctl daemon-reload
sudo systemctl enable sonarqube.service
sudo systemctl start sonarqube.servicesystemctl status sonarqube.service --no-pager
sudo journalctl -u sonarqube.service -n 160 --no-pager- sysctl 결과가 변경 전 값보다 작지 않고 공식 최소값 이상입니다.
- 서비스 계정이 필요한 경로만 읽고 쓸 수 있습니다.
- systemd-analyze verify가 성공했습니다.
- 로그에 SonarQube is operational 또는 정상 기동 상태가 확인됩니다.
active 직후에도 DB 마이그레이션과 검색 인덱스 초기화가 진행될 수 있습니다. HTTP 상태와 로그가 정상 완료될 때까지 외부 트래픽을 연결하지 않습니다.
로컬 API, DB 세션, 두 번째 HTTPS 접속을 검증합니다.
로컬 상태와 HTTPS 프록시 이중 검증
로컬 9000 상태 API와 TLS 프록시를 각각 확인합니다. 첫 관리자 로그인에서는 즉시 기본 비밀번호를 변경하고 실제 분석은 제한된 테스트 프로젝트로 수행합니다.
curl --fail --silent --show-error http://127.0.0.1:9000/api/system/statussudo ss -lntp | grep -E ':(9000|9001)[[:space:]]'sudo -u postgres psql -d sonarqube -c "SELECT usename, application_name, state FROM pg_stat_activity WHERE datname = 'sonarqube';"curl --fail --silent --show-error --head https://<SONAR_PUBLIC_HOST>/curl --fail --silent --show-error https://<SONAR_PUBLIC_HOST>/api/system/status- 로컬·HTTPS 상태 API가 모두 UP을 반환합니다.
- 9000은 127.0.0.1에만 리슨하고 외부에는 TLS 프록시만 노출됩니다.
- PostgreSQL 세션 사용자가 sonarqube 전용 역할입니다.
- 첫 로그인 즉시 기본 관리자 비밀번호를 변경했습니다.
- 테스트 프로젝트 분석과 재분석이 성공했습니다.
로컬 API는 정상인데 HTTPS만 실패하면 SonarQube를 재시작하지 말고 프록시 upstream, 인증서, X-Forwarded 헤더를 점검합니다.
권한·TLS·백업·업데이트 정책을 운영 기준으로 잠급니다.
접근·비밀·백업 경계 강화
외부에는 TLS 프록시의 주 포트만 공개하고 SonarQube·Elasticsearch·PostgreSQL 포트는 사설망 또는 루프백으로 제한합니다. 전역 Execute Analysis와 관리자 권한을 조직 정책에 맞게 줄입니다.
sudo stat -c '%U %G %a %n' /etc/sonarqube/sonarqube.env /opt/sonarqube/conf/sonar.properties /etc/systemd/system/sonarqube.servicesudo ss -lntup | grep -E ':(5432|9000|9001)[[:space:]]'systemd-analyze security sonarqube.servicesudo journalctl -u sonarqube.service -p warning --since today --no-pager- DB·검색·웹 내부 포트를 공인망에 노출하지 않았습니다.
- 프록시가 X-Forwarded-Proto와 X-Forwarded-For를 전달하고 CA 서명 TLS를 사용합니다.
- 환경 파일과 백업에 대한 읽기 권한을 최소화했습니다.
- 기본 관리자 비밀번호와 분석 토큰을 회전·만료 정책에 넣었습니다.
- PostgreSQL 논리·물리 백업과 SonarQube 데이터 복구를 실제 테스트했습니다.
SonarQube data 디렉터리만 복사해도 PostgreSQL과 일관된 전체 복구가 보장되지 않습니다. DB 백업이 핵심이며 검색 인덱스는 공식 복구 절차에 따라 재구축할 수 있게 합니다.
장애 시 새 시작을 반복하지 말고 서비스 중지와 백업 복원 분기로 이동합니다.
서비스 격리와 설정·데이터 보존
실패하면 프록시 upstream에서 먼저 제외하고 SonarQube를 정상 중지합니다. PostgreSQL DB와 /var/lib/sonarqube를 삭제하거나 새 DB로 덮어쓰지 않습니다.
sudo systemctl stop sonarqube.service
systemctl is-active sonarqube.servicesudo cp --preserve=all /opt/sonarqube/conf/sonar.properties.<BACKUP_SUFFIX>.bak /opt/sonarqube/conf/sonar.properties기존 설치의 같은 변경 시점 백업이 있는 분기에서만 실행합니다.sudo cp --preserve=all /etc/systemd/system/sonarqube.service.<BACKUP_SUFFIX>.bak /etc/systemd/system/sonarqube.service기존 설치 분기에서만 실행합니다.sudo cp --preserve=all /etc/sysctl.d/99-sonarqube.conf.<BACKUP_SUFFIX>.bak /etc/sysctl.d/99-sonarqube.conf
sudo sysctl -p /etc/sonarqube/sysctl.<BACKUP_SUFFIX>.previous기존 파일을 변경했고 백업과 변경 전 런타임 기록이 모두 있는 경우에만 실행합니다. 복원한 persistent 파일의 다른 키는 이 단계에서 함께 재적용하지 않습니다.sudo mv --no-clobber /etc/sysctl.d/99-sonarqube.conf /etc/sysctl.d/99-sonarqube.conf.disabled.<BACKUP_SUFFIX>
sudo sysctl -p /etc/sonarqube/sysctl.<BACKUP_SUFFIX>.previous기존 99-sonarqube.conf 백업이 없는 최초 설치 분기에서만 실행합니다. 변경 전 기록 파일이 없거나 내용이 검증되지 않으면 실행하지 않습니다.sudo cp --preserve=all /etc/sonarqube/sonarqube.env.<BACKUP_SUFFIX>.bak /etc/sonarqube/sonarqube.env기존 설치의 같은 변경 시점 백업이 있을 때만 실행하고 root:sonarqube 0640을 다시 확인합니다.sudo mv --no-clobber /etc/sonarqube/sonarqube.env /etc/sonarqube/sonarqube.env.disabled.<BACKUP_SUFFIX>백업이 없는 최초 설치 분기에서만 실행하며 비밀 파일을 삭제하지 않습니다.sudo systemctl disable sonarqube.service최초 설치 롤백 분기에서 실행합니다.sudo mv --no-clobber /etc/systemd/system/sonarqube.service /etc/systemd/system/sonarqube.service.disabled.<BACKUP_SUFFIX>최초 설치 분기에서만 실행하며 DB·설치·데이터·로그는 보존합니다.sudo systemctl daemon-reloadsudo du -sh /var/lib/sonarqube /var/log/sonarqube
sudo -u postgres psql -Atc "SELECT datname FROM pg_database WHERE datname='sonarqube';"- 프록시에서 신규 요청을 차단한 뒤 서비스를 중지했습니다.
- 기존 설치는 같은 변경 시점의 설정·유닛·JDBC 비밀 파일만 복원했습니다.
- sysctl은 이 가이드의 파일만 반영했고, 롤백 때도 기록한 변경 전 값 또는 기존 파일만 적용했습니다.
- 최초 설치는 자동 시작·유닛·JDBC 비밀 파일만 비활성화했습니다.
- PostgreSQL DB, 데이터, 로그, 비밀 파일을 삭제하지 않았습니다.
- DB 스키마가 이전 SonarQube 버전과 호환되는지 확인 전 구버전을 시작하지 않았습니다.
SonarQube 업그레이드가 DB 스키마를 변경했다면 바이너리만 되돌리는 것은 안전하지 않습니다. 호환성 문서와 검증된 DB 백업 없이는 이전 버전을 시작하지 않습니다.
지원되는 복구 지점과 원인을 확정한 뒤 별도 복제 환경에서 복원 검증을 수행합니다.
SECURITY CHECK
운영 전 마지막 보안 점검
- SonarQube를 root로 실행하지 않고 전용 계정과 경로 권한을 사용한다.
- JDBC 비밀번호를 명령 인자·sonar.properties·저장소에 넣지 않는다.
- 9000·9001·5432를 공인망에 노출하지 않고 TLS 프록시만 공개한다.
- 기본 관리자 자격증명과 분석 토큰을 즉시 회전하고 권한을 최소화한다.
- PostgreSQL 백업과 실제 복원 시험을 SonarQube 업그레이드 전 수행한다.
COMMON ERRORS
자주 막히는 지점
Elasticsearch bootstrap 실패
- 증상
- vm.max_map_count 또는 파일 한계 오류로 서비스가 종료됩니다.
- 가능한 원인
- 호스트 sysctl·systemd LimitNOFILE·LimitNPROC가 공식 최소값보다 작습니다.
- 확인 순서
- 현재 값을 확인하고 공식 최소값을 적용한 뒤 유닛 검증 후 한 번만 재시작합니다.
PostgreSQL 연결 실패
- 증상
- JDBC 오류 또는 인증 실패로 SonarQube가 기동하지 않습니다.
- 가능한 원인
- 지원 버전, pg_hba, DNS, TLS, 역할 비밀번호 또는 DB 소유권이 맞지 않습니다.
- 확인 순서
- 서비스 계정의 네트워크 경로와 PostgreSQL 로그를 확인하고 비밀번호를 명령줄에 노출하지 않습니다.
프록시에서 502
- 증상
- 로컬 API는 되지만 외부 HTTPS가 502를 반환합니다.
- 가능한 원인
- upstream 주소·포트, 프록시 헤더 또는 SonarQube 초기화 완료 전 연결이 원인입니다.
- 확인 순서
- 127.0.0.1 상태 API와 프록시 로그·upstream을 순서대로 확인합니다.
PRIMARY REFERENCES
공식 문서
- SonarQube Server — 지원 데이터베이스 설치
- SonarQube Server 2026.1 LTA — Linux 사전 요구사항
- SonarQube Server — ZIP 기본 설치
- SonarQube Server — systemd 서비스 실행
- SonarQube Server — TLS 역방향 프록시 보안
설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.