title: How to install JupyterHub with Docker on a local machine and in a sub domain
body: <p>I will run JupyterHub in a sub domain. Here is the Dockerfile, jupyterhub_config.py, .gitlab-ci.yml. 
  My first question is how to configure the jupyter_config.py. How can I load the jupyterhub_config.py on the build in the container?</p>
  
  <p>How do I start Jupyterhub in the .gitlab-ci.yml for tests and how do I copy the application in the sub domain? I wrote a README.md. I need a little help for the JupyterHub. If all works fine, I will write a complete HOWTO Install JupyterHub on a local machine and in a sub domain by a provider. </p>
  
  <pre><code>FROM continuumio/miniconda3
  
  # Updating packages
  RUN apt-get update -y \
      &amp;&amp; apt-get install -y --no-install-recommends \
         git \
         nano \
         unzip \
      &amp;&amp; apt-get clean \
      &amp;&amp; rm -rf /var/lib/apt/lists/*
  
  # Install conda and Jupyter
  RUN conda update -y conda
  RUN conda install -c conda-forge jupyter_nbextensions_configurator \
      jupyterhub \
      jupyterlab \
      matplotlib \
      pandas \
      scipy
  
  # Setup application
  EXPOSE 8000
  
  CMD ["jupyterhub", "--ip='*'", "--port=8000", "--no-browser", "--allow-root"]
  </code></pre>
  
  <p>The .gitlab-ci.yml</p>
  
  <pre><code>image: docker:latest
  
  variables:
    CONTAINER_IMAGE: registry.gitlab.com/joklein
    DOCKER_IMAGE: jupyterhub
    TAG: 0.1.0
  
  services:
    - docker:dind
  
  stages:
    - build
    - test
    - release
    - deploy
  
  before_script:
    - echo "$GITLAB_PASSWORD" | docker login registry.gitlab.com --username $GITLAB_USER --password-stdin
  
  build:
    stage: build
    script:
      - docker build -t $CONTAINER_IMAGE/$DOCKER_IMAGE .
      - docker push $CONTAINER_IMAGE/$DOCKER_IMAGE
  
  test:
    stage: test
    script:
      - docker pull $CONTAINER_IMAGE/$DOCKER_IMAGE
        #    - docker run $CONTAINER_IMAGE/$DOCKER_IMAGE -dt -p 8000:8000 --name $DOCKER_IMAGE
  
  release:
    stage: release
    script:
      - docker pull $CONTAINER_IMAGE/$DOCKER_IMAGE
      - docker tag  $CONTAINER_IMAGE/$DOCKER_IMAGE:latest $CONTAINER_IMAGE/$DOCKER_IMAGE:$TAG
      - docker push $CONTAINER_IMAGE/$DOCKER_IMAGE:$TAG
    only:
      - master
  
  deploy:
    stage: deploy
    image: alpine:latest
    before_script:
      - apk update &amp;&amp; apk add git openssh-client rsync
    script:
      - mkdir .public
      - cp -r * .public
      - mv .public public
      - mkdir "${HOME}/.ssh"
      - echo "${SSH_HOST_KEY}" &gt; "${HOME}/.ssh/known_hosts"
      - echo "${SSH_PRIVATE_KEY}" &gt; "${HOME}/.ssh/id_rsa"
      - chmod 700 "${HOME}/.ssh/id_rsa"
      - rsync -hrvz --delete --exclude=_ public/ user@example.com:www/jupyter/
    only:
      - master
  </code></pre>
  
  <p>The jupyterhub_config.py</p>
  
  <pre><code>c = get_config()
  # Letsencrypt (https://letsencrypt.org/) to obtain a free, trusted SSL
  # certificate.
  c.JupyterHub.ssl_key = '/etc/letsencrypt/live/example.com/privkey.pem'
  c.JupyterHub.ssl_cert = '/etc/letsencrypt/live/example.com/fullchain.pem'
  c.JupyterHub.port = 443
  #
  # Change from JupyterHub to JupyterLab
  c.Spawner.default_url = '/lab'
  c.Spawner.debug = True
  #
  # # Specify users and admin
  c.Authenticator.whitelist = {"systemuser"}
  c.Authenticator.admin_users = {"systemuser"}
  </code></pre>
  
  <h1>Docker base image of JupyterHub and JupyterLab</h1>
  
  <p>JupyterHub is a multi-user server for Jupyter notebooks. JupyterLab is the
  next-generation web-based user interface for the Jupyter Project. This
  JupyterHub is a <a href="https://docker.com" rel="nofollow noreferrer">Docker</a> base image for <a href="https://jupyterhub.readthedocs.io/en/stable" rel="nofollow noreferrer">JupyterHub</a> and <a href="https://jupyterlab.readthedocs.io/en/stable" rel="nofollow noreferrer">JupyterLab</a>
  that works as a stand-alone application and in a (sub) domain.</p>
  
  <p>Images derived from this image can either run as a stand-alone server, or
  function as a volume image for your server. You can also use them in a CI/CD
  system such as GitLab CI to build your content prior to bundling it into a
  standalone server container.</p>
  
  <h2>Building your JupyterHub image</h2>
  
  <p>Based on this structure, you can easily build an image for your needs. There are two options for using the image you generated:</p>
  
  <ul>
  <li>as a stand-alone image</li>
  <li>as a volume image for your webserver</li>
  </ul>
  
  <p>The simplest way to build your own image is to use a Dockerfile. This is only an example. If you need more software packages you can install them with this
  Dockerfile and conda.</p>
  
  <h3>Build the container</h3>
  
  <p><code>docker build -t juypterhub .</code></p>
  
  <p>Your JupyterHub with JupyterLab is automatically generated during this build.</p>
  
  <h3>Run the container</h3>
  
  <p><code>docker run -p 8000:8000 -d --name jupyterhub jupyterhub jupyterhub</code></p>
  
  <ul>
  <li><code>-p</code> is used to map your <code>local port 8000</code> to the <code>container port 8000</code></li>
  <li><code>-d</code> is used to run the container in background. JupyterHub will just write
  logs so no need to output them in your terminal unless you want to troubleshoot a server error.</li>
  <li><code>-- name jupyterhub</code> names your container jupyterhub</li>
  <li><code>jupyterhub</code> the image</li>
  <li><code>jupyterhub</code> is the last command used to start the jupyterhub server</li>
  </ul>
  
  <p>and your <code>JupyterHub</code> with <code>Jupyterlab</code> is now available of <code>http://localhost:8000</code>.</p>
  
  <h3>Start / Stop JupyterHub</h3>
  
  <p><code>docker start / stop juyterhub</code></p>
  
  <h2>Configure JupyterHub</h2>
  
  <h3>Let's encrypt certificates for JupyterHub</h3>
  
  <p>To enable HTTPS on your website, you need to get a certificate (a type of file) from a Certificate Authority (CA). Let’s Encrypt is a CA. In order to get a certificate for your website’s domain from Let’s Encrypt, you have to
  demonstrate control over the domain. With Let’s Encrypt, you do this using
  software that uses the ACME protocol, which typically runs on your web host.</p>
  
  <p>Change to <a href="https://zerossl.com" rel="nofollow noreferrer">zerossl.com</a> and generate a certificate for your domain. As the
  result you get four files, <strong>domain-key.txt</strong>, <strong>domain-crt.txt</strong>, domain-csr.txt, account-key.txt. This files uses base 64, which is readable in
  ASCII, not binary format. The certificates are already in PEM format. Just
  change the extension to *.pem.</p>
  
  <p>For JupyterHub only the files domain-key.txt and domain-crt are needed.</p>
  
  <p><code>cp domain-crt.txt fullchain.pem</code><br>
  <code>cp domain-key.txt privkey.pem</code></p>
  
  <h3>Add a System user in the container</h3>
  
  <p>By default JupyterHub searches for users on the server. In order to be able to
  log in to our new JupyterHub server we need to connect to the JupyterHub docker
  container and create a new system user with a password.</p>
  
  <p><code>docker exec -it jupyterhub bash</code><br>
  <code>useradd --create-home systemuser</code><br>
  <code>passwd systemuser</code><br>
  <code>exit</code></p>
  
  <p>The command <code>docker exec -it jupyterhub bash</code> will spawn a root shell in your
  docker container. <strong>You can use the root shell to create system users in the
  container</strong>. These accounts will be used for authentication in JupyterHub's
  default configuration.</p>
  
  <p>The first command useradd creates a new user named systemuser. The second will
  ask you for a password.</p>