Configure SSL for Sonarqube running on Docker container to enable https

I am trying to switch from HTTP to HTTPS on my instance of Sonarqube running on a Docker container. I am using Docker Swarm with a docker-compose.yml file to deploy the container. I have my hostname.crt and hostname.jks certs created and ready for use. I have not found any documentation on environment variables that can be set in the docker-compose to enable SSL. The closest resource I have found is here with HTTPS_PROXYHOST and HTTPS_PROXYPORT variables, but it is unclear how these would be used.
https://docs.sonarqube.org/latest/setup/environment-variables/

Current docker compose below:

version: "3"
services:
  sonarqube:
    image: '<hostname>:9091/sonarqube:8.3-community'
    ports:
      - '9000:9000'
    environment:
      - sonar.jdbc.username=sonarqube
      - sonar.jdbc.password=<password>
      - sonar.jdbc.url=jdbc:sqlserver://<hostname>;databaseName=sonar
      - sonar.updatecenter.activate=false
    volumes:
      - '/u01/docker_data/sonarqube/conf:/opt/sonarqube/conf'
      - '/u01/docker_data/sonarqube/data:/opt/sonarqube/data'
      - '/u01/docker_data/sonarqube/logs:/opt/sonarqube/logs'
      - '/u01/docker_data/sonarqube/extensions:/opt/sonarqube/extensions'
    depends_on:
      - sonarqube_mssql
    deploy:
      placement:
        constraints:
          - node.hostname == <hostname>
  sonarqube_mssql:
    image: '<hostname>:9091/microsoft/mssql-server-linux'
    ports:
      - '1433:1433'
    environment:
      - ACCEPT_EULA=Y
      - MSSQL_PID=Express
      - MSSQL_SA_PASSWORD=<password>
    volumes:
      - '/u01/docker_data/mssql:/var/opt/mssql'
    deploy:
      placement:
        constraints:
          - node.hostname == <hostname>

Hi @dkapoor ,

welcome to the community :wave:

i would suggest to add a reverse proxy / load balancer in front of sonarqube and terminate tls before forwarding the traffic to the sonarqube service. you can find some docs here.
For docker to get you a fast start you can to turn to the all mighty nginx-proxy. just make sure that you increase the client_max_body_size when using this image :wink:

as for your compose: the environment variables seems odd to me. i think they should look something like this

SONAR_JDBC_URL: jdbc:sqlserver://<hostname>;databaseName=sonar
SONAR_JDBC_USERNAME: sonarqube
SONAR_JDBC_PASSWORD: <password>
SONAR_UPDATECENTER_ACTIVATE: false

hope that helps you a little bit

Thanks for the response @Tobias_Trabelsi,

I am trying to get nginx-proxy set up in front of SonarQube as you suggested. To configure the proxy, I am making edits to the default.conf file and mounting it to the
nginx docker container. Currently, http://<hostname>:80 is rerouting to my SonarQube instance at http://<hostname>:9000, so I know that nginx is at least somewhat functional. However, I have not been able to set it up so that only https traffic routes to SonarQube. Any idea on how to configure this? Also, the environment variables I set have been working in my SonarQube so far - maybe there are different types of syntax that work.

My edits to the default.conf file and nginx docker-compose are shown below. Any additional help is greatly appreciated.

default.conf:

...
server {
  # port to listen on. Can also be set to an IP:PORT
  listen 80;

  # sets the domain[s] that this vhost server requests for
  # this line is throwing a warning "server name "https://<hostname>:9000" has suspicious symbols in /etc/nginx/default.conf:56"
  server_name https://<hostname>:9000;

  location / {
    proxy_pass http://<hostname>:9000;
  }
}

nginx docker-compose.yml:

version: '3'

services:
  nginx-proxy:
    image: '<hostname>/jwilder/nginx-proxy:latest'
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - /u01/nginx/default.conf:/etc/nginx/default.conf
      - /u01/nginx/nginx.conf:/etc/nginx/nginx.conf
    deploy:
      placement:
        constraints:
          - node.hostname == <hostname>
  whoami:
    image: jwilder/whoami
    environment:
      - VIRTUAL_HOST=whoami.local

Hi @dkapoor ,

i think you misunderstood the intention of the reverse proxy here. take this compose as an example:

version: "3"
services:
  sonarqube:
    image: '<hostname>:9091/sonarqube:8.3-community'
    environment:
      SONAR_JDBC_URL: jdbc:sqlserver://<hostname>;databaseName=sonar
      SONAR_JDBC_USERNAME: sonarqube
      SONAR_JDBC_PASSWORD: <password>
      SONAR_UPDATECENTER_ACTIVATE: false
      VIRTUAL_HOST: <FQDN>
      VIRTUAL_PORT: 9000
    volumes:
      - '/u01/docker_data/sonarqube/conf:/opt/sonarqube/conf'
      - '/u01/docker_data/sonarqube/data:/opt/sonarqube/data'
      - '/u01/docker_data/sonarqube/logs:/opt/sonarqube/logs'
      - '/u01/docker_data/sonarqube/extensions:/opt/sonarqube/extensions'
    depends_on:
      - sonarqube_mssql
    network:
      - sonarnet
    deploy:
      placement:
        constraints:
          - node.hostname == <hostname>
  sonarqube_mssql:
    image: '<hostname>:9091/microsoft/mssql-server-linux'
    environment:
      ACCEPT_EULA: Y
      MSSQL_PID: Express
      MSSQL_SA_PASSWORD: <password>
    volumes:
      - '/u01/docker_data/mssql:/var/opt/mssql'
    network:
      - sonarnet
    deploy:
      placement:
        constraints:
          - node.hostname == <hostname>
  proxy:
    image: jwilder/nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - /u01/docker_data/nginx/unrestricted_client_body_size.conf:/etc/nginx/conf.d/unrestricted_client_body_size.conf:ro
      - /u01/docker_data/nginx/certs/:/etc/nginx/certs:ro
    networks:
      - sonarnet
      - public
    deploy:
      placement:
        constraints:
          - node.hostname == <hostname>
networks:
  sonarnet:
  public:
    driver: bridge

you see that the compose now only exposes port 80 (http) and 443 (https). The certificates should be stored into /u01/docker_data/nginx/certs/ and use the convention as described here.
the content of the config that is mounted inside the reverse proxy should be tweaked to your company guidlines. for testing you can set it to something like this: client_max_body_size 0;

1 Like

Thanks @Tobias_Trabelsi, I managed to get things working with your help! The docker-compose that worked for me isn’t exactly the same as what you posted, so I’ll post mine here in case anyone has the same issue. Now I can access my SonarQube with the URL https://<hostname>:9000/, but not with http://<hostname>:9000/ which is exactly the result I was looking for. From my understanding, VIRTUAL_PORT: 9000 is being exposed and then the mapped port on nginx is routing traffic to this port. But I do not know exactly what is happening, can you help clarify how this solution works?

docker-compose.yml:

version: "3"
services:
  sonarqube:
    image: '<hostname>/sonarqube:8.3-community'
    ports:
      - '9001:443'
    environment:
      - sonar.jdbc.username=sonarqube
      - sonar.jdbc.password=<password>
      - sonar.jdbc.url=jdbc:sqlserver://<hostname>;databaseName=sonar
      - sonar.updatecenter.activate=false
      - VIRTUAL_HOST=<hostname>
      - VIRTUAL_PORT=9000
    volumes:
      - '/u01/docker_data/sonarqube/conf:/opt/sonarqube/conf'
      - '/u01/docker_data/sonarqube/data:/opt/sonarqube/data'
      - '/u01/docker_data/sonarqube/logs:/opt/sonarqube/logs'
      - '/u01/docker_data/sonarqube/extensions:/opt/sonarqube/extensions'
      - '/u01/keystore:/u01/keystore'
    depends_on:
      - sonarqube_mssql
    deploy:
      placement:
        constraints:
          - node.hostname == <hostname>
  sonarqube_mssql:
    image: '<hostname>/microsoft/mssql-server-linux'
    ports:
      - '1433:1433'
    environment:
      - ACCEPT_EULA=Y
      - MSSQL_PID=Express
      - MSSQL_SA_PASSWORD=<password>
    volumes:
      - '/u01/docker_data/mssql:/var/opt/mssql'
    deploy:
      placement:
        constraints:
          - node.hostname == <hostname>
  proxy:
    image: '<hostname>/jwilder/nginx-proxy'
    ports:
      - "9000:443"
    volumes:
      - '/var/run/docker.sock:/tmp/docker.sock:ro'
      - '/u01/docker_data/nginx/unrestricted_client_body_size.conf:/etc/nginx/conf.d/unrestricted_client_body_size.conf:ro'
      - '/u01/keystore/:/etc/nginx/certs:ro'
    deploy:
      placement:
        constraints:
          - node.hostname ==<hostname>

Also, accessing http://<hostname>:9000/ shows the following. Is there any way to make it instead resolve to nothing at all?

# 400 Bad Request
The plain HTTP request was sent to HTTPS port
nginx/1.17.6

Hi @dkapoor ,

this is one way to do it if you want to keep the port, but in general (this would also solve your problem with http-> https redirection) it would be cleaner to get rid of it.
the VIRTUAL_PORT variable is parsed by the template engine of the reverse proxy in order to know which port the http traffic should be routed to in the internal docker network if there are multiple expose statements in the Dockerfile.
When you map port 80 to 80 and 443 to 443 in the reverse proxy, every traffic that is coming in via http on port 80 is redirected with a 301 to the https port and schema.

hope that clears stuff up (:

Thanks @Tobias_Trabelsi,

I was looking to see if there was a way to disable HTTP in the SonarQube configuration files. The docs here say that setting the sonar.web.port=-1 disables HTTP connections.
https://docs.sonarqube.org/display/SONARQUBE45/Running+SonarQube+Over+HTTPS

However, setting sonar.web.port=-1 in the /sonarqube/conf/sonar.properties file throws this error. Do you have any idea why this is happening?

docker service logs sonarqube_sonarqube:

2020.06.25 18:36:33 WARN  web[][o.s.p.ProcessEntryPoint] Fail to start web
sonarqube_sonarqube.1.inuur8t6pzq9@<hostname>    | java.lang.IllegalStateException: HTTP port '-1' is invalid

Also, I tried mapping 80:80 and 443:443 in the reverse proxy, and that seems to break SonarQube. It only seems to be working with 9000:443

Hi @dkapoor ,

the docs are for sonarqube version 4.5 and this option is not valid anymore.
can you describe what you mean with “breaks sonarqube” ? because it is running just fine for me with this settings

Hey @Tobias_Trabelsi,

Thanks, I should have paid attention to the version. I actually did end up getting SonarQube running with 80:80 and 443:443. These are the nginx settings in the docker-compose:

  proxy:
    image: '<hostname>/jwilder/nginx-proxy'
    ports:
      - "443:443"
      - "80:80"
    volumes:
      - '/var/run/docker.sock:/tmp/docker.sock:ro'
      - '/u01/docker_data/nginx/unrestricted_client_body_size.conf:/etc/nginx/conf.d/unrestricted_client_body_size.conf:ro'
      - '/u01/keystore/:/etc/nginx/certs:ro'
    deploy:
      placement:
        constraints:
          - node.hostname == <hostname>

Thanks for all of the help - I have one last question to get a clean result. Currently, http://hostname:443` is redirecting to the following page. We are worried that this could be a security vulnerability since it shows the version of nginx. Do you have any idea how we would avoid showing this page, or how to hide the version of nginx?

nginx

1 Like

Hi @dkapoor ,

you can remove the version using server_tokens off;. like the unrestricted_client_body_size.conf file you can just mount an additional file in the container or have both settings in one file and mount them to /etc/nginx/conf.d/

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.