Liferay 7.3 Release

Vor kurzem wurde Liferay 7.3 released und ich muss sagen die Startupzeit und im allgemeinen die Performance hat sich stark verbessert. Wer nun selber schnell mal testen will und einen Reverse Proxy davor geschaltet hat, der muss etwas beachten, damit das Zusammenspiel von Liferay und dem Reverse Proxy NginX problemlos funktioniert.

Die Einrichtung des Reverse Proxy NginX

##################################
#                                #
# Liferay Service                #
#                                #
##################################

# Redirect http -> https
server {
    listen 80;
    server_name liferay.XXX.org;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;

    server_name liferay.XXX.org;

    # logging
    error_log /var/log/nginx/liferay_error.log debug;
    access_log /var/log/nginx/liferay_access.log;

    include /etc/nginx/only_internal_access.conf;

    location / {
        # only internal access
        include only_internal_access.conf;

        proxy_pass http://192.168.2.1:9999;
        proxy_set_header Host $host;
    }

    # SSL
    include ssl/*.XXX.org;
}

Docker Compose Skript

Schauen wir uns nun das Docker Compose Skript dazu an. Es kommt hier das offizielle Image von Liferay https://hub.docker.com/r/liferay/portal zum Einsatz.

Das Skript ist super einfach gehaltet, aber eine wichtige Option ist eingebaut worden. Damit HTTPS korrekt über den Reverse Proxy funktioniert, muss die Umgebungsvariable LIFERAY_WEB_PERIOD_SERVER_PERIOD_PROTOCOL gesetzt werden. Diese mappt dann beim Starten direkt in die portal.properties, sodass hier sehr einfach Änderungen von außen durchgeführt werden können. Durch das Setzen auf HTTPS werden alle URLs mit dem HTTPS Protokoll versehen und Liferay funktioniert so hinter dem Reverse Proxy einwandfrei.

Ansonsten werden aus dem lokalen Verzeichnis noch die 3 Mountpoints eingehangen. So lässt sich zum Beispiel schnell ein JAR deployen. Kopieren sie es einfach in den Deploy Ordner. Da in dem Container AutoDeploy aktiv ist, wird das automatisch in die Liferay Instanz deployt.

version: '3'
services:
  liferay:
    image: liferay/portal:7.3.0-ga1
    ports:
      - "9999:8080"
    environment:
      - LIFERAY_WEB_PERIOD_SERVER_PERIOD_PROTOCOL=https
    volumes:
      - ./volumes/files:/mnt/liferay/files
      - ./volumes/scripts:/mnt/liferay/scripts
      - ./volumes/deploy:/mnt/liferay/deploy

Privates Docker Repository mit Nexus

Ziel soll es sein ein secure repository für Docker Images bereitzustellen. In der Sprache von Docker bedeutet dieses, dass das Repository über HTTPS angesprochen wird. Dieses soll privat sein, da es nicht öffentliche Images beinhalten soll. Dazu werden 2 + 1 Domainnames benötigt, da wir ein Mapping in den Nexus Container auf unterschiedliche Ports vornehmen müssen. In diesem Beispiel gibt es die Hostnamen nexus, docker und docker-proxy.

FQDN Port
nexus.XXX.org 9000
docker.XXX.org 9001
docker-proxy.XXX.org 9002

Den NginX Reverse Proxy konfigurieren

Dazu benötigen wir folgende Einstellungen für den NGinX Reverse Proxy:

###############################
#                             #
# Public Nexus Repository     #
#                             #
# nexus.XXX.org               #
#                             #
###############################

#    
# Nexus Server
# map to port 9000
#

# Redirect http -> https
server {
    listen 80;
    server_name nexus.XXX.org;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;

    server_name nexus.XXX.org;

    # logging
    error_log /var/log/nginx/nexus_error.log debug;
    access_log /var/log/nginx/nexus_access.log;

    # Push large objects to nexus
    client_max_body_size 2G;

    # SSL
    include ssl/*.XXX.org;

    location / {
      # Use IPv4 upstream address instead of DNS name to avoid attempts by nginx to use IPv6 DNS lookup
      proxy_pass http://127.0.0.1:9000/;
      proxy_set_header Host $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;
    }

}

#    
# Docker Repository
# map to port 9001
#

server {
    listen 443 ssl http2;

    server_name docker.XXX.org;

    # logging
    error_log /var/log/nginx/nexus_docker_error.log debug;
    access_log /var/log/nginx/nexus_docker_access.log;

    # Push large objects to nexus
    client_max_body_size 2G;

    # SSL
    include ssl/*.XXX.org;

    # optimize downloading files larger than 1G
    #proxy_max_temp_file_size 2G;

    location / {
      # Use IPv4 upstream address instead of DNS name to avoid attempts by nginx to use IPv6 DNS lookup
      proxy_pass http://127.0.0.1:9001/;
      proxy_set_header Host $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; 
    }

}

#    
# Docker Proxy
# map to port 9002
#

server {
    listen 443 ssl http2;

    server_name docker-proxy.XXX.org;

    # logging
    error_log /var/log/nginx/nexus_docker_error.log debug;
    access_log /var/log/nginx/nexus_docker_access.log;

    # Push large objects to nexus
    client_max_body_size 2G;

    # SSL
    include ssl/*.XXX.org;

    location / {
      # Use IPv4 upstream address instead of DNS name to avoid attempts by nginx to use IPv6 DNS lookup
      proxy_pass http://127.0.0.1:9002/;
      proxy_set_header Host $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; 
    }

}

Nexus Repository erstellen

Damit Docker Images gespeichert werden können, muss zunächst ein neues Repository vom Typ Docker Host angelegt werden. Wichtig hierbei ist, dass das Repostitory auf einen HTTP Connector mit dem Port aus dem Mapping, also 9002, übereinstimmt. Es muss auch nur der HTTP Connector sein, da wir uns per HTTPS auf dem Reverse Proxy später anmelden.

Docker Login

Um die Konfiguration zu Testen, kann man Docker Login verwenden.

docker login docker.XXX.org

Docker Proxy

Aufgrund eines Bugs in Nexus, ist die Konfiguration von Nexus für einen Docker Proxy nicht ganz so einfach, wie man es sich wünschen würde und es hat auch eher den Character eines Hacks.

Wie bereits oben beschrieben, ist ein weiterer Port 9002 in dem Mapping vorhanden. Der FQDN docker-proxy.XXX.org ist auf den Port 9002 gemappt.

In Nexus erstellen Sie nun ein weiteres Repository (Docker-Proxy) und vergeben dem Repository den Port 9002.

Szenrio

Gegeben sei eine Domain die bei dem DynDNS Provider duckdns.org gehostet wird. Es sind aber als Einschränkung bei DuckDNS nur maximal 5 SubDomains erlaubt.

Eine Lösung – Pfade verwenden

Eine Lösung kann sein, dass man eine SubDomain verwendet, um über die Pfade den Dienst mit Hilfe des Reverse Proxys aufzulösen.

Hier nun der Server Abschnitt um einen Dienst der in dem lokalen Netz auf der IP Addresse 192.168.2.2 Port 4711 lauscht. Diesen werden wir auf der Domain xxx.duckdns.org/service bekannt machen.

server {
    listen 80;
    server_name xxx.duckdns.org;

    #
    # Serve service on path http://xxx.duckdns.org/service and map it to 192.168.2.2:4711
    #
    location /service/ 
    {
        proxy_set_header        Host $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;

        proxy_pass              http://192.168.2.2:4711/;

        proxy_read_timeout      600s;
        proxy_send_timeout      600s;
    }
}

Die proxy_pass Anweisung ist hier der wichtige Teil. Hiermit bestimmt man wo der Dienst erreichbar ist.

Gitea Dienst unter git.xxx.org soll mit SSL Verschlüsselung ausgestattet werden. Es werden verschiedene Domains auf dem Server bedient. Als Reverse Proxy ist bereits NginX vorgeschaltet. Daher muss nicht einmal die Gitea Konfiguration geändert werden. Es kann über NginX die Verschlüsselung mit SSL geschehen.

Die LetsEncrypt Initiative macht es sehr einfach Webseiten mit einem gültigen Zertifikat auszustellen. Dazu gibt es verschiedene Clients die die Verwaltung vornehmen. Ich verwende hier den Certbot.

Installation Certbot unter Arch Linux

yaourt -S --noconfirm certbot-nginx

Erstellen eines Zertifikates

Das Plugin für Certbot parst das ConfigFile von NginX und zeigt alle Domains an, die auf dem Server einen eigenen Serverblock besitzen. Da wir die Konfiguration nicht verändern wollen, rufen wir den certbot mit dem Parameter certonly auf. Damit wird nur ein Zertifikat für die gewählten Domains erstellt. Hierfür muss man natürlich im Besitz der Domain sein.

certbot --nginx certonly

[root@server conf]# certbot --nginx certonly
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): xxx@web.de

-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: A

-------------------------------------------------------------------------------
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about EFF and
our work to encrypt the web, protect its users and defend digital rights.
-------------------------------------------------------------------------------
(Y)es/(N)o: Y

Which names would you like to activate HTTPS for?
-------------------------------------------------------------------------------
1: ----
2: git.xxx.org
3: ----
-------------------------------------------------------------------------------
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 2
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for mrpeacockgit.duckdns.org
2018/06/02 09:50:20 [notice] 9946#9946: signal process started
Waiting for verification...
Cleaning up challenges
2018/06/02 09:50:25 [notice] 9948#9948: signal process started

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/git.xxx.org/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/git.xxx.org/privkey.pem
Your cert will expire on 2018-08-31. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
Donating to EFF:                    https://eff.org/donate-le

Wie man in der Ausgabe erkennen kann, legt der certbot unterhalb /etc/letsencrypt/live/ für jede Domain ein Verzeichnis an. In diesem wird das Zertifikat und der private Schlüssel abgelegt.

Einbinden des Zertifikates in NginX

Die Konfiguration für den Gitea Service ist in eine eigene Datei ausgelagert. Diese wird per Include Anweisung eingebunden. Hierfür ist ein separates conf-Verzeichnis unterhalb /etc/nginx/ ratsam.

#
# Gitea Service
#
include conf/git.conf;

Damit alte Links bzw. der direkte Aufruf mit dem unverschlüsselten HTTP Protokoll weiterhin funtkioniert muss eine 301 Weiterleitung eingerichtet werden.

# Redirect http -> https
server {
    listen 80;
    server_name git.xxx.org;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;

    server_name git.xxx.org;

    # logging
    error_log /var/log/nginx/gitea_error.log debug;
    access_log /var/log/nginx/gitea_access.log;

    client_max_body_size 100M; # Push large Objects to gitea

    # Configuration for letsencrypt
    location ^~ /.well-known/acme-challenge/ {
        allow all;
        root /var/lib/letsencrypt/;
        default_type "text/plain";
        try_files $uri =404;
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
    }

    # SSL
    ssl on;
    ssl_certificate /etc/letsencrypt/live/git.xxx.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/git.xxx.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

Konfiguration von Gitea

Da in diesem Beispiel NGinX als Reverse Proxy vorgeschaltet ist, muss hier nur die Root URL angepasst werden. Es ist HTTPS als Protokoll und 443 als Port anzugeben. Gitea selbst arbeitet weiterhin mit dem HTTP Protokoll.

[server]
; Listen protocol. One of 'http', 'https', 'unix' or 'fcgi'.
PROTOCOL                   = http
DOMAIN                     = git.xxx.org
ROOT_URL                   = https://git.xxx.org:443/

Wildcard Zertifikate

In einem anderen Artikel beschreibe ich wie man lokale Dienste mit einem Wildcard Zertifikat absichern kann. Hierfür setzte ich den freien DNS Dienst DuckDNS ein.