diff --git a/README.md b/README.md index ea4f910..6ad9593 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,33 @@ -# CodeScene on Docker + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Overview](#overview) +- [Install](#install) + - [Generate a self-signed certificate](#generate-a-self-signed-certificate) + - [Provide a custom SSL certificate](#provide-a-custom-ssl-certificate) + - [Path prefix](#path-prefix) +- [Run](#run) + - [Run CodeScene behind the reverse proxy](#run-codescene-behind-the-reverse-proxy) + - [Use](#use) + - [Stop](#stop) +- [License, Liability & Support](#license-liability--support) +- [Analyze this this project on CodeScene](#analyze-this-this-project-on-codescene) + + + +# Overview This repository is an example of how to run CodeScene in a Docker instance behind an nginx reverse proxy. Even if you are not using Docker, the nginx configuration may be helpful for running CodeScene behind nginx. -`docker-compose` is used here to run two Docker images, one running +`docker-compose` is used here to run two Docker containers, one running nginx, the other with CodeScene itself. The [CodeScene -Dockerfile](docker-codescene/Dockerfile) can also be used by itself to +docker image](https://hub.docker.com/r/empear/codescene) can also be used by itself to run CodeScene directly. -## Install +# Install This assumes that you have a working Docker installation. @@ -18,172 +36,29 @@ Clone this repository and go to the top level directory. git clone git@github.com:empear-analytics/docker-codescene-nginx-self-signed-ssl.git cd docker-codescene-nginx-self-signed-ssl -### Prepare the host and reverse proxy configuration for Letsencrypt SSL certificate +To use it you have to either generate a self-signed certificate, or provide a real certificate. -Install certbot on the host according to the instructions found here: https://certbot.eff.org/lets-encrypt/ubuntubionic-other -Replace `**domain_name**` with your correct domain name in docker-nginx/nginx.conf - -The complete code is available in the `using_letsecrypt_ssl` branch - see https://github.com/empear-analytics/docker-codescene-nginx-self-signed-ssl/commit/1db5245b40b10ee954e3b23261f40b6e29a4b665. - -## Build - -The reverse proxy using Nginx is built like this: - - docker build -t reverseproxy docker-nginx/ - -The CodeScene image should already be available from [Docker Hub](https://hub.docker.com/r/empear/ubuntu-onprem/) under -`empear/ubuntu-onprem:latest`, but can also be built locally like this: - - docker build -t empear/ubuntu-onprem docker-codescene/ - -If you want to use a specific version of CodeScene, you can add a `--build-arg`: - - docker build --build-arg CODESCENE_VERSION=3.X.Y -t empear/ubuntu-onprem docker-codescene/ - -## Run - -### Run CodeScene behind the reverse proxy - -Use `docker-compose` to start both instances: - - docker-compose up -d - -### Run CodeScene by itself without the reverse proxy: - - docker pull empear/ubuntu-onprem - docker run -i -t -p 3003 \ - --name myname \ - --mount type=bind,source=$PWD/docker-codescene/codescene,destination=/codescene \ - empear/ubuntu-onprem - -To connect to this instance: - - docker exec -i -t myname /bin/bash - - -### Bind mount and/or Docker volume - -In both the reverse proxy setup and the standalone version, the -`/codescene` directory is bound to the -[`docker-codescene/codescene`](docker-codescene/codescene) directory -in this repository. It contains two directories, `repos` and -`analyses` that can be used to store Git repositories and the analysis -result files that CodeScene produces. CodeScene's internal database is -also stored in `/codescene`, as well as a logfile. By using these directories, your data -will be persisted beyond the life of the Docker container. - -Both the standalone command presented above and the `docker-compose` configuration use the `bind` mount type, for -ease of demonstration and debugging. In a production setting, [Docker -volumes](https://docs.docker.com/storage/volumes) would be a better -solution. - -The configuration presented here uses CodeScene's optional environment -variables `CODESCENE_ANALYSIS_RESULTS_ROOT` and -`CODESCENE_CLONED_REPOSITORIES_ROOT`. Their purpose is to ensure that users cannot create -repositories or store analysis results outside of the `/codescene` -directory. In conjunction with the `CODESCENE_DB_PATH`, we can be sure -that all the necessary data for persisting CodeScene is in a single, -easy-to-manage location. You can of course adjust these variables to -fit your specific needs. - -Whether you use volumes or bind mounts, they must be passed to the -Docker container at run time. - -In the full reverse proxy setup using `docker-compose`, this is done -in the `volumes` stanza of the configuration. The -[`docker-compose.yml`](docker-compose.yml) file in this repository -uses a Docker volume. To use a bind mount with `docker-compose`, or -for more detailed instructions, please refer to the documentation -[here](https://docs.docker.com/compose/compose-file/#volumes). - -For the standalone configuration using a bind mount, see [Run -CodeScene by itself without the reverse -proxy](#run-codescene-by-itself-without-the-reverse-proxy). To use a -Docker volume in the standalone configuration, you must first [create -a volume](https://docs.docker.com/storage/volumes/#create-and-manage-volumes): - - docker volume create codescene-volume - -This volume can then be referenced when starting the Docker container: - - docker run -i -t -p 3003 \ - --name myname \ - --mount type=volume,source=codescene-volume,target=/codescene \ - empear/ubuntu-onprem - -Please refer to the [Docker documentation](https://docs.docker.com/storage/volumes) -for instructions on managing your Docker volumes. - - -### Authentication for remote Git repositories - -To analyze code located on remote servers, CodeScene needs to be able -to clone it with Git. For public repositories, cloning via `https` is -sufficient. Private repositories will require authentication -credentials, for which SSH keys are the recommended form. (For -example, including user credentials in Git URLs is inherently insecure -for requests of an open network.) - -However, it can be tricky to communicate SSH credentials to a Docker -container in a way that allows CodeScene to run unattended. Here are -some options. - -#### Keys without a passphrase - -If you are comfortable using SSH keys that do not require a -passphrase, the simplest solution is to bind a valid `.ssh` directory -on the host system to `/root/.ssh` inside the container. - -With the standalone setup, this would mean supplying an additional -`--mount` argument to `docker run`, something like: - -``` ---mount type=bind,source=$HOME/codescene-git-keys,destination=/root/.ssh -``` - -With the `docker-compose` solution, you would add the following to the -`volumes` section of the `codescene` stanza: - -``` - -"${HOME}/codescene-git-keys:/root/.ssh" -``` - -The directory at `$HOME/codescene-git-keys` could be tested outside of -Docker to be sure that the SSH connection works correctly. Make sure -that `known_hosts` contains a reference to the servers you will be -cloning from. - -#### GitHub deploy keys - -For greater security, if your remote code is on GitHub, the solution -above could be combined with GitHub's [deploy keys](https://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys). - -#### Linux host: ssh-agent forwarding - -When running on a Linux host, it may be possible to forward the host -machine's `ssh-agent` to the Docker container by mounting a volume -corresponding to $SSH_AUTH_SOCK (untested): +## Generate a self-signed certificate +Generate a self-signed certificate in the `nginx/conf.d` folder with a command like ``` ---mount type=bind,source=$(dirname $SSH_AUTH_SOCK),destination=$(dirname $SSH_AUTH_SOCK) \ --e SSH_AUTH_SOCK=$SSH_AUTH_SOCK +openssl req -subj '/CN=localhost' -x509 -newkey rsa:4096 -nodes \ + -keyout nginx/conf.d/mycert.key \ + -out nginx/conf.d/mycert.crt -days 365 ``` -#### Dedicated ssh-agent containers -You may be able to use a dedicated Docker container to store SSH credentials. See: +## Provide a custom SSL certificate +Place the ssl certificate and private key files in the *nginx/conf.d* folder to make them accessible in the nginx container. +Update the *nginx/conf.d/reverseproxy.conf* file with `ssl_certificate` and `ssl_certificate_key` set to your certificate and key file names, and with `server_name` set to match your certificate. -- [uber-common/docker-ssh-forward](https://github.com/uber-common/docker-ssh-agent-forward) -- [nadeas/ssh-agent](https://github.com/nardeas/ssh-agent) - -### Path prefix +## Path prefix In some situations, it may be necessary to run CodeScene under a path rather than at the root, eg. `example.com/codescene` rather than simply `example.com`. -To do this, you can use the `CODESCENE_PATH_PREFIX` by setting it in -the [Dockerfile](docker-codescene/Dockerfile). The prefix you add +To do this, you can use the `CODESCENE_PATH_PREFIX` environment variable. The prefix you add there will be appended to all internal links in CodeScene. If you were to use this solution in conjunction with nginx, your [nginx.conf](docker-nginx/nginx.conf) file might include something like this: @@ -199,79 +74,34 @@ location /codescene/ { } ``` +# Run +## Run CodeScene behind the reverse proxy -### Memory settings - -To adjust memory settings for CodeScene running inside a container, -you can set the `JAVA_OPTIONS` environment variable. - -To set "max heap" explicitly use `-Xmx`: - -``` -# with explicit max memory => notice that -m 500M is ignored -docker run -p3103:3003 -m 500M -e JAVA_OPTIONS='-Xmx300m' --name codescene empear/ubuntu-onprem -VM settings: - Max. Heap Size: 300.00M - Ergonomics Machine Class: server - Using VM: OpenJDK 64-Bit Server VM -``` - -To let the JVM autodetect default settings based on the container's memory: - -``` -# with experimental options and autodetection -# note that -XX:+UseCGroupMemoryLimitForHeap has been deprecated -docker run -p3103:3003 -m 500M -e \ - JAVA_OPTIONS='-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2' \ - --mount type=bind,source=$PWD/docker-codescene/codescene,destination=/codescene \ - --name codescene empear/ubuntu-onprem -VM settings: - Max. Heap Size (Estimated): 222.50M - Ergonomics Machine Class: server - Using VM: OpenJDK 64-Bit Server VM -``` - -Please note, that -[support for `-XX:+UseCGroupMemoryLimitForHeap` has been deprecated in JDK 10](https://bugs.openjdk.java.net/browse/JDK-8194086) -and is no longer needed. - -For more details, see -[Java inside docker: What you must know to not FAIL](https://developers.redhat.com/blog/2017/03/14/java-inside-docker/). +Use `docker-compose` to start both instances: + docker-compose up -d -### Timezones -CodeScene, in general, uses default system's timezone. -In our docker image we set the default timezone explicitly to UTC via [`CODESCENE_TIMEZONE` env var](https://github.com/empear-analytics/docker-codescene-nginx-self-signed-ssl/blob/master/docker-codescene/Dockerfile#L30). -This can be overriden when the docker image is run: -``` -docker run -p3003 -e CODESCENE_TIMEZONE='Europe/Stockholm' empear/ubuntu-onprem -``` -Note that if you use docker-compose you need to leave out quotes: -``` - environment: - - CODESCENE_TIMEZONE=Europe/Stockholm -``` -### Use +## Use Browse to https://localhost. In order to use CodeScene, you will need a license. You can get a license on the [Empear Customer Portal](https://portal.empear.com/). For more information about CodeScene, see the [CodeScene Documentation](https://docs.enterprise.codescene.io/). -### Stop +## Stop To stop the reverse proxy: docker-compose down -### License, Liability & Support +# License, Liability & Support * The contents of this repository are provided under the [MIT License](https://github.com/empear-analytics/docker-codescene-nginx-self-signed-ssl/blob/master/LICENSE.md). Other licences may apply to the software contained in the Docker images referenced here. -### Analyze this this project on CodeScene +# Analyze this this project on CodeScene [![](https://codescene.io/projects/2554/status.svg) Get more details at **codescene.io**.](https://codescene.io/projects/2554/jobs/latest-successful/results) diff --git a/docker-codescene/Dockerfile b/docker-codescene/Dockerfile deleted file mode 100644 index 99a747f..0000000 --- a/docker-codescene/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -FROM ubuntu:18.10 - -# To workaround git authentication issues with libcurl 7.61.0 installed with 18.10 -# Azure DevOps clone fails with personal access tokens -> see https://github.com/Microsoft/Git-Credential-Manager-for-Mac-and-Linux/issues/102 -RUN echo "deb http://security.ubuntu.com/ubuntu/ bionic-security main restricted" >> /etc/apt/sources.list - -RUN apt-get update; apt-get install -y git openjdk-11-jdk locales libcurl3-gnutls=7.58.0* - -# debugging utilities -RUN apt-get update; apt-get install -y netcat rlwrap - -## because this is Docker, we can just set these without bothering -## with most of the locale infrastructure -ENV LANG C.UTF-8 -ENV LANGUAGE C.UTF-8 -ENV LC_ALL C.UTF-8 -ENV LC_CTYPE C.UTF-8 - -RUN mkdir -p /opt/codescene - -ARG CODESCENE_VERSION=4.0.5 -ADD https://downloads.codescene.io/enterprise/${CODESCENE_VERSION}/codescene-enterprise-edition.standalone.jar /opt/codescene/ -EXPOSE 3003 - -# separate script used because we want to support custom JAVA_OPTIONS variable -ADD start-codescene.sh /start-codescene.sh -RUN chmod 755 /start-codescene.sh - -ENV CODESCENE_DIR /codescene -ENV CODESCENE_DB_PATH=${CODESCENE_DIR}/codescene -ENV CODESCENE_ANALYSIS_RESULTS_ROOT=${CODESCENE_DIR}/analysis -ENV CODESCENE_CLONED_REPOSITORIES_ROOT=${CODESCENE_DIR}/repos -ENV CODESCENE_TIMEZONE UTC - -## Enable to run CodeScene with a path prefix -#ENV CODESCENE_PATH_PREFIX /codescene - -ENTRYPOINT [ "/start-codescene.sh" ] diff --git a/docker-codescene/codescene/analysis/.gitignore b/docker-codescene/codescene/analysis/.gitignore deleted file mode 100644 index 86d0cb2..0000000 --- a/docker-codescene/codescene/analysis/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore \ No newline at end of file diff --git a/docker-codescene/codescene/caacs_enterprise.db.mv.db b/docker-codescene/codescene/caacs_enterprise.db.mv.db deleted file mode 100644 index 65fdb9d..0000000 Binary files a/docker-codescene/codescene/caacs_enterprise.db.mv.db and /dev/null differ diff --git a/docker-codescene/codescene/repos/.gitignore b/docker-codescene/codescene/repos/.gitignore deleted file mode 100644 index 86d0cb2..0000000 --- a/docker-codescene/codescene/repos/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore \ No newline at end of file diff --git a/docker-codescene/start-codescene.sh b/docker-codescene/start-codescene.sh deleted file mode 100644 index 3499224..0000000 --- a/docker-codescene/start-codescene.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -set -x - -mkdir -p $CODESCENE_ANALYSIS_RESULTS_ROOT -mkdir -p $CODESCENE_CLONED_REPOSITORIES_ROOT -# don't quote "$JAVA_OPTIONS" because you wouldn't be able to use it for multiple properties/settings in docker-compose.yml -java -XshowSettings:vm $JAVA_OPTIONS -XX:MaxRAMPercentage=75 -Duser.timezone="$CODESCENE_TIMEZONE" -jar "/opt/codescene/codescene-enterprise-edition.standalone.jar" | tee -a ${CODESCENE_DIR}/codescene.log diff --git a/docker-compose.yml b/docker-compose.yml index 1bdbcf0..f0984eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,19 +1,21 @@ version: '3.2' services: - reverseproxy: - image: reverseproxy - ports: - - 443:443 - restart: always + reverseproxy: + depends_on: + - codescene + image: nginx:1.19 + ports: + - 443:443 + restart: always + volumes: + - ./nginx/conf.d:/etc/nginx/conf.d - codescene: - depends_on: - - reverseproxy - image: empear/ubuntu-onprem:latest - restart: always - volumes: - - "./docker-codescene/codescene:/codescene" + codescene: + image: empear/codescene:latest + restart: always + volumes: + - ./codescene:/codescene # environment: # raise codescene log level for troubleshooting # - CODESCENE_LOG_LEVEL=DEBUG diff --git a/docker-nginx/Dockerfile b/docker-nginx/Dockerfile deleted file mode 100644 index f48c2cf..0000000 --- a/docker-nginx/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM alpine:3.7 - -# -# PACKAGES -# -COPY docker-entrypoint.sh /opt/docker-entrypoint.sh -COPY nginx.conf /nginx/ -RUN apk add --no-cache \ - bash \ - nginx \ - shadow \ - openssl && \ - chmod u+rx,g+rx,o+rx,a-w /opt/docker-entrypoint.sh && \ - usermod -u 10777 nginx && \ - groupmod -g 10777 nginx && \ - mkdir -p /opt/www && \ - mkdir -p /opt/ssl && \ - chown -R nginx:nginx /opt/ && \ - mkdir -p /nginx/tmp/ && \ - chown -R nginx:nginx /nginx/ - -# -# RUN NGINX -# -EXPOSE 443 -VOLUME ["/opt/www"] -WORKDIR /opt/www/ -ENTRYPOINT ["/opt/docker-entrypoint.sh"] -CMD ["nginx", "-c", "/nginx/nginx.conf", "-g", "daemon off;"] diff --git a/docker-nginx/LICENSE.md b/docker-nginx/LICENSE.md deleted file mode 100644 index 24d5dad..0000000 --- a/docker-nginx/LICENSE.md +++ /dev/null @@ -1,9 +0,0 @@ -# The MIT License (MIT) - -Copyright (c) 2018 Empear AB - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/docker-nginx/README.md b/docker-nginx/README.md deleted file mode 100644 index 79ade13..0000000 --- a/docker-nginx/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# docker-codescene-nginx-self-signed-ssl - -Docker-Image to run nginx as a proxy with a self-signed SSL certificate. diff --git a/docker-nginx/docker-entrypoint.sh b/docker-nginx/docker-entrypoint.sh deleted file mode 100644 index f92afa1..0000000 --- a/docker-nginx/docker-entrypoint.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -e - -echo ">> DOCKER-ENTRYPOINT: GENERATING SSL CERT" - -cd /opt/ssl/ -openssl genrsa -des3 -passout pass:x -out server.pass.key 2048 -openssl rsa -passin pass:x -in server.pass.key -out server.key -rm server.pass.key -openssl req -new -key server.key -out server.csr -subj "/C=SE/ST=Skane/L=Malmo/O=codescene.io/OU=codescene.io/CN=local.codescene.io" -openssl x509 -req -sha256 -days 300065 -in server.csr -signkey server.key -out server.crt -cd /opt/www/ - -echo ">> DOCKER-ENTRYPOINT: GENERATING SSL CERT ... DONE" -echo ">> DOCKER-ENTRYPOINT: EXECUTING CMD" - -exec "$@" diff --git a/docker-nginx/nginx.conf b/docker-nginx/nginx.conf deleted file mode 100644 index 1dd6d81..0000000 --- a/docker-nginx/nginx.conf +++ /dev/null @@ -1,61 +0,0 @@ -error_log /nginx/tmp/error.log; - -pid /nginx/tmp/nginx.pid; - -worker_processes 1; - -events { - worker_connections 1024; -} - -http { - client_body_temp_path /nginx/tmp/client_body; - fastcgi_temp_path /nginx/tmp/fastcgi_temp; - proxy_temp_path /nginx/tmp/proxy_temp; - scgi_temp_path /nginx/tmp/scgi_temp; - uwsgi_temp_path /nginx/tmp/uwsgi_temp; - - sendfile off; - - tcp_nopush on; - tcp_nodelay on; - # increase read timeout to avoid 504 when cloning larger repos on the "New Project" page - proxy_read_timeout 600; - keepalive_timeout 65; - types_hash_max_size 2048; - - include /etc/nginx/mime.types; - index index.html index.htm index.php; - - log_format main '$remote_addr - $remote_user [$time_local] $status ' - '"$request" $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - default_type application/octet-stream; - - server { - listen 443; - ssl on; - ssl_certificate /opt/ssl/server.crt; - ssl_certificate_key /opt/ssl/server.key; - ssl_session_cache shared:SSL:10m; - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_prefer_server_ciphers on; - server_name local.codescene.io; - index index.html index.htm; - root /opt/www; - access_log /nginx/tmp/access.log; - error_log /nginx/tmp/error.log; - - location / { - # upstream hostname is service name in docker-compose.yml - proxy_pass http://codescene:3003; - - proxy_redirect http:// $scheme://; - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - } -} diff --git a/nginx/conf.d/reverseproxy.conf b/nginx/conf.d/reverseproxy.conf new file mode 100644 index 0000000..5149592 --- /dev/null +++ b/nginx/conf.d/reverseproxy.conf @@ -0,0 +1,33 @@ + +server { + listen 80; + listen [::]:80; + server_name _; + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl; + ssl_certificate /etc/nginx/conf.d/mycert.crt; + ssl_certificate_key /etc/nginx/conf.d/mycert.key; + ssl_session_cache shared:SSL:10m; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + server_name local.codescene.io; + index index.html index.htm; + root /opt/www; + + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + proxy_cookie_path / "/; secure"; + + location / { + # upstream hostname is service name in docker-compose.yml + proxy_pass http://codescene:3003; + + proxy_redirect http:// $scheme://; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +}