Projector is a way to run IntelliJ IDEA on a remote server. Recently, I wrote an article about this , but I kept silent about the important thing for any paranoid - encrypting data on a web socket.

Generating and padding keys is a rather dreary piece of work. Here you will have to get acquainted with the features of Docker and cryptography in Java. Unfortunately, you cannot escape from this anywhere, because it is Java, and the guys from JetBrains are not at all to blame.

In the original article, this text was closed by a spoiler, but then I felt that it was impossible to read such a wall of text and gave birth to this text. Sorry in advance. By opening this article you agree that you will not like what you see.

Key Hereration

First we need to generate a set of keys. To do this, install OpenJDK and use the keytool tool.

Key generation is a task consisting of a bunch of steps. For myself, I wrote a script , and I urge you to use it.

mkdir ~/keystore cd ~/keystore curl --output./keymaker chmod 755./keymaker./projectile-keymaker projector idea true IP mypassword 

However, nothing prevents you from doing this yourself. The main thing is that the output will be two important files: CDMY0CDMY and CDMY1CDMY.

  • CDMY2CDMY is our Certificate Authority by which server keys are signed. You will need to make the browser trust it.
  • CDMY3CDMY is a certificate of a specific server running IDEA.

Manual Sunrise

A true paranoid never believes any other people's scripts on the Internet, and checks everything on his own. Let's go over the basic steps.

First we need to generate our own Certificate Authority (CA), which we will then push into all browsers.

keytool -genkeypair -v \ -alias ca \ -dname "CN=myCA, OU=Development, O=myCA, L=SPB, S=SPB, C=RU" \ -keystore ca.jks \ -keypass:env PW \ -storepass:env PW \ -keyalg RSA \ -keysize 4096 \ -ext KeyUsage:critical="keyCertSign" \ -ext BasicConstraints:critical="ca:true" \ -validity 9999 

A little digression about passwords

Pay attention to this line: CDMY4CDMY. This means that we enter the password not in the console (otherwise it will be lost in bash history), but we will take it from environment variables.

You can write CDMY5CDMY and that’s enough, but then it will also get lost in bash history. It’s much more logical to put it in a file.

For example, this is how you can generate a random password and put it in a file:

export PW=`pwgen -Bs 10 1` echo $PW > password 

And this is how you can suck it back into the environment variable:

export PW=`cat password` 

Beautiful, right? Of course, such a file can still be stolen from the server’s hard drive, but this is a completely different story. Throughout this article, I will drink my pills and imagine that storing passwords in a text file is normal. Moreover, we do not need a file, but only the contents of the CDMY6CDMY environment variable.

Go back to the key generation.

CA, we generated, but in some kind of nasty JKS format that browsers don’t understand. So that you can feed it to the browser, first you need to overtake it in the usual crt:

keytool -export -v \ -alias ca \ -file ca.crt \ -keypass:env PW \ -storepass:env PW \ -keystore ca.jks \ -rfc 

It's time to generate a key for our server (the one that will show the Idea):

keytool -genkeypair -v \ -alias server \ -dname "CN=myServer, OU=Development, O=myServer, L=SPB, S=SPB, C=RU" \ -keystore server.jks \ -keypass:env PW \ -storepass:env PW \ -keyalg RSA \ -keysize 2048 \ -validity 385 

There is a certificate, but it is not signed yet and therefore it will not work in the browser. Continuing the ceremony, we create a request for signature:

keytool -certreq -v \ -alias server \ -keypass:env PW \ -storepass:env PW \ -keystore server.jks \ -file server.csr 

Now the server certificate can be signed by the CA that we created at the very beginning:

keytool -gencert -v \ -alias ca \ -keypass:env PW \ -storepass:env PW \ -keystore ca.jks \ -infile server.csr \ -outfile server.crt \ -ext KeyUsage:critical="digitalSignature,keyEncipherment" \ -ext EKU="serverAuth" \ -ext SAN="IP:" \ -rfc 

Note that the SAN can be in two versions: either "DNS:" if you have a registered domain name. Or "IP:" if there is no domain. If there is no IP or domain, you just have to hide in a corner and cry, without this entry the browser will not believe you.

Next, in the opposite direction, we need to make our JKS trust the self-signed CA (otherwise the next step will break):

keytool -import -v \ -alias ca \ -file ca.crt \ -keystore server.jks \ -storetype JKS \ -storepass:env PW << EOF yes EOF 

We take the previously signed certificate and pack it inside JKS:

keytool -import -v \ -alias server \ -file server.crt \ -keystore server.jks \ -storetype JKS \ -storepass:env PW 

And finally, the result of your torment can be viewed directly in the console:

keytool -list -v \ -keystore server.jks \ -storepass:env PW 

In my humble opinion, the torment with the set of these codes in the console is not worth it.Better take a ready-made script and correct it as you like.

We write the configuration files

To store the settings, you need to make the CDMY7CDMY file with the following contents:

STORE_TYPE=JKS FILE_PATH=/tmp/server.jks STORE_PASSWORD=mypassword KEY_PASSWORD=mypassword 

The password, obviously, must be specified exactly the same as that you used when creating the keystor.

In this article, I write the full path to my home directory (CDMY8CDMY) so that it doesn't seem to you that I cheated on you somewhere and missed a piece of text. Be critical of what you read and write your paths. Well, or you can change the name and surname to CDMY9CDMY, although I will be a little uncomfortable.

Why CDMY10CDMY and not CDMY11CDMY? Because we are in this form, in a temporary folder, we will mount it inside the docker image. You’ll see everything now.

Now we need to tell Projector to start using these files. To do this, set special environment variables with nonhumanoid names in the CDMY12CDMY parameters, and mount the files inside the image.

We go to the repository downloaded in advance, open the CDMY13CDMY file and look for the line:

docker run --rm -p 8080:8080 -p 8887:8887 -it "$containerName" bash -c "nginx &&./" 

There you need to add two environment variables:

  • CDMY14CDMY points to the settings file;
  • CDMY15CDMY sets the password that must be specified in the URL in order to connect successfully;
  • We mount both files (settings and keystor) in CDMY16CDMY.

docker run --rm \ -v/home/olegchir/keystore/ \ -v/home/olegchir/keystore/server.jks:/tmp/server.jks \ --env ORG_JETBRAINS_PROJECTOR_SERVER_SSL_PROPERTIES_PATH=/tmp/ \ --env ORG_JETBRAINS_PROJECTOR_SERVER_HANDSHAKE_TOKEN=mypassword \ -p 8080:8080 -p 8887:8887 -it "$containerName" bash -c "nginx &&./" 

Now you can run the container!


There may be some errors at startup. It is advisable to read the log and find lines like:

[INFO] :: ProjectorServer :: WebSocket SSL is enabled:/tmp/ [INFO] :: ProjectorServer :: Server started 

Install the certificate in browsers

Copy the CDMY17CDMY file to the device from where you want to connect. Next, you need to open a browser and install a certificate.

Installing a certificate on different combinations of the browser and the operating system may look different. I cannot talk about all possible combinations in this article, but I will mention the most popular ones.


  1. Settings
  2. Tab Privacy & amp; Security
  3. At the very bottom of the settings is the View Certificates button
  4. Authorities Tab
  5. Import button.
  6. We are looking for a certificate in the file selection dialog
  7. Click, all available daws.
  8. Finish the import.

ITKarma picture

Chrome for Windows:

  1. Settings
  2. Privacy and security section
  3. Securty Section
  4. Manage certificates button
  5. Trusted Root Certification Authorities Tab
  6. Import button.
  7. The wizard opens, select the file, agree to import it into the Trusted Root Certification Authorities.
  8. After import, be sure to close Chrome. On Windows, this can be tricky. When you close Chrome, open the Task Manager and see if there are any processes with the name Chrome left. All such processes must be killed with the Delete button.
  9. After restarting Chrome, everything should work.

ITKarma picture

Chrome for Linux:

  1. Settings
  2. Privacy and security section
  3. Securty Section
  4. Manage certificates button
  5. Authorities Tab
  6. Import button.
  7. Select the CDMY18CDMY file,
  8. Click, all available daws.
  9. Finish the import.

Chrome and Fully Kiosk Browser for Android:

Installation for Android can be very different. On Huawei MediaPad M5, it was enough for me to click a finger on a certificate in the Solid Explorer file manager and it was installed almost like on a computer.

On other devices, you can try this way:

  1. Settings
  2. Security & amp; privacy
  3. More Settings
  4. Encription and credentials
  5. Install from storage
  6. Select CDMY19CDMY
  7. Finish the import.

It is important to understand that each manufacturer of an Android device is its own master, and the "Install from storage" item may appear anywhere in the settings and be called by any name. I’ll have to tinker with it.

Connect from the browser

For the local machine: https://localhost: 8080/projector/? wss & amp; token=mypassword

For the cloud server: https://hostname: 8080/projector/? wss & amp; host=hostname & amp; port=8887 & amp; token=mypassword

Search for problems

If all else fails, try opening the CDMY20CDMY address and see what the browser writes. It’s possible there will be a button like "trust this server forever anyway" or something like that. There may be a talking error message.


Setting up a secure connection is long and unpleasant. You need to type in the console a lot of commands that cannot be memorized, rummage inside dockerfiles, transfer files to a mobile device. If you made a mistake somewhere in at least one letter, then nothing works.

On the other hand, once did - and live in peace.