Edit icon Edit This Page

Enabling HTTPS

Repsy Open Source can serve HTTPS itself. HTTPS is optional and is switched on per port: it adds two ports next to the HTTP ones and never replaces them, so the HTTP ports 8080 and 9090 stay open.

HTTPS portServesHTTP counterpartVariable that turns it on
8443The web UI8080API_SSL_ENABLED
9443The package protocols (Maven, npm, Docker, …)9090REPO_SSL_ENABLED

If you already run a reverse proxy, let it terminate TLS instead and keep Repsy on plain HTTP behind it. See Running Behind a Reverse Proxy.

Why you want HTTPS

Package clients send your username and password, or a deploy token, with every request. Over plain HTTP anyone on the network path can read them. Some clients also refuse to work without HTTPS:

  • Go refuses to send credentials to an http:// URL (refusing to pass credentials to insecure URL) and has no option to override this. A private Go repository is only usable over HTTPS.
  • Docker only talks plain HTTP to a registry on the loopback address (localhost). For any other host it expects HTTPS, and docker login fails with http: server gave HTTP response to HTTPS client. See Docker over plain HTTP.
  • Helm needs --plain-http for an OCI registry that has no HTTPS.

Get a keystore

Repsy reads the certificate and its private key from a Java keystore file. The default format is PKCS12; JKS also works if you set the keystore type. Repsy does not read PEM files directly.

If you have a PEM certificate chain and private key, for example from Let’s Encrypt or your company CA, convert them into a PKCS12 keystore. The name repsy is the alias Repsy looks for by default:

openssl pkcs12 -export \
  -in fullchain.pem \
  -inkey privkey.pem \
  -name repsy \
  -out keystore.p12 \
  -passout pass:<keystore-password>

For a first test you can generate a self-signed certificate instead. See Generating a self-signed certificate.

Make the keystore readable by the container

The container runs as the non-root user appuser. The keystore file must be readable by that user, or Repsy fails to start with FileNotFoundException: ... (Permission denied). A file with mode 644 is enough:

chmod 644 keystore.p12

Mount the file read-only into /app/certs, a directory the image already provides for certificates.

Start Repsy with HTTPS enabled

docker run -d \
  --name repsy \
  -p 8080:8080 -p 8443:8443 \
  -p 9090:9090 -p 9443:9443 \
  -e STORAGE_BASE_PATH=/app/data/storage \
  -v repsy-data:/app/data \
  -v "$PWD/keystore.p12:/app/certs/keystore.p12:ro" \
  -e API_SSL_ENABLED=true \
  -e API_SSL_KEY_STORE_PATH=file:/app/certs/keystore.p12 \
  -e API_SSL_KEY_STORE_PASSWORD=<keystore-password> \
  -e REPO_SSL_ENABLED=true \
  -e REPO_SSL_KEY_STORE_PATH=file:/app/certs/keystore.p12 \
  -e REPO_SSL_KEY_STORE_PASSWORD=<keystore-password> \
  -e REPO_BASE_URL=https://<your-repsy-host>:9443 \
  repo.repsy.io/repsy/os/repsy:latest

Both ports can use the same keystore, as here, or two different ones. Set REPO_BASE_URL to the HTTPS address of the package port so that the connection snippets in the web UI, and the tarball addresses of the npm registry, use it. See Running Behind a Reverse Proxy.

Check the result

Open https://<your-repsy-host>:8443 in a browser, or check both ports from a shell:

curl -I https://<your-repsy-host>:8443/
curl -i https://<your-repsy-host>:9443/v2/

The first call answers 200. The second answers 401 with a WWW-Authenticate: Bearer realm="https://..." header that names your HTTPS address: that is the Docker registry asking for credentials.

Settings

Each port has its own set of variables. Replace API with REPO for the package port.

VariableDefaultMeaning
API_SSL_ENABLEDfalseTurns HTTPS on for the web UI port.
API_SSL_KEY_STORE_PATHemptyPath of the keystore file, for example file:/app/certs/keystore.p12. Required when HTTPS is on.
API_SSL_KEY_STORE_PASSWORDemptyPassword of the keystore.
API_SSL_KEY_STORE_TYPEPKCS12Keystore type. JKS also works.
API_SSL_KEY_ALIASrepsyAlias of the key entry inside the keystore.
API_SSL_KEY_PASSWORDemptyPassword of the private key, only when it differs from the keystore password.
API_SSL_PORT8443Leave at the default. See the note below.

REPO_SSL_PORT defaults to 9443.

  • Key password. A PKCS12 keystore created by keytool or openssl uses one password for the keystore and the key. Leave *_SSL_KEY_PASSWORD empty for it: setting a different value makes the start fail with UnrecoverableKeyException. The variable exists for keystores whose key has its own password, which is common with JKS.
  • Alias. If the keystore has no entry under the alias, Repsy stops with Alias name [<alias>] does not identify a key entry. Set *_SSL_KEY_ALIAS to the alias keytool -list -keystore keystore.p12 shows.
  • Renewing a certificate. Repsy reads the keystore when it starts. After you replace the file, restart the container.

Keep API_SSL_PORT at 8443 and REPO_SSL_PORT at 9443. Repsy routes requests by the port they arrive on, and only these two HTTPS ports are wired to the web UI and to the package protocols. With another value the connector starts, but the routes of that port answer 404. To serve HTTPS on a different public port, publish the container port on it, for example -p 443:8443.

If HTTPS is enabled but the keystore is missing, unreadable or its password is wrong, Repsy does not start. The container exits and the log ends with the reason, for example Caused by: java.io.FileNotFoundException: /app/certs/keystore.p12 (No such file or directory) or Caused by: java.io.IOException: keystore password was incorrect.

Generating a self-signed certificate

A self-signed certificate is fine for a first test. Clients only accept it when you tell them to trust it, so use a certificate from a public or company CA for anything else.

keytool -genkeypair \
  -alias repsy \
  -keyalg RSA \
  -keysize 2048 \
  -storetype PKCS12 \
  -keystore keystore.p12 \
  -validity 365 \
  -storepass <keystore-password> \
  -dname "CN=<your-repsy-host>, O=Repsy" \
  -ext "SAN=DNS:<your-repsy-host>,IP:<ip-address>"

The SAN entry must contain the exact host name or IP address that clients use. Export the certificate so that clients can trust it:

keytool -exportcert -rfc -alias repsy -keystore keystore.p12 -storepass <keystore-password> -file repsy.pem

Making clients trust your certificate

With a certificate from a public CA, clients work without any change. With a self-signed or company CA certificate, each client must be told to trust it. Without that, clients report errors such as x509: certificate signed by unknown authority (Go and Docker) or PKIX path building failed (Java). Each tool has its own setting:

ClientHow to trust a certificate
curlcurl --cacert repsy.pem https://...
DockerCopy the certificate to /etc/docker/certs.d/<host>:<port>/ca.crt on the machine that runs the Docker daemon.
GoSet SSL_CERT_FILE=/path/to/repsy.pem.
Maven and GradleImport the certificate into a Java truststore and pass -Djavax.net.ssl.trustStore=<file>.
npmSet cafile=/path/to/repsy.pem in .npmrc.

Check the documentation of your tool for the other clients.

Docker over plain HTTP

Prefer HTTPS for Docker. If you only evaluate Repsy on a machine that is not localhost, you can tell the Docker daemon to accept plain HTTP for that registry. Add it to /etc/docker/daemon.json and restart the daemon:

{
  "insecure-registries": ["<your-repsy-host>:9090"]
}

This sends credentials and images unencrypted. Do not use it for a shared or production instance.

Was this page helpful?