Skip to content

Commit

Permalink
feat: Support xpra as additional connection method for remote containers
Browse files Browse the repository at this point in the history
[xpra](https://github.com/Xpra-org/xpra/) allows to run X11 programs in
the Docker container and expose them to the local host.

We make use of [xpra-html5] client, which allows us to access the
application in the browser - without any external software like Guacamole
on the way.

xpra runs as non-root out of the box. Basic authentication is handled via
nginx.
  • Loading branch information
MoritzWeber0 committed Dec 6, 2023
1 parent dde12dd commit 8f076c4
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 39 deletions.
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,9 @@ run-capella/remote: capella/remote
docker run $(DOCKER_RUN_FLAGS) \
-v $$(pwd)/volumes/workspace:/workspace \
-e RMT_PASSWORD=$(RMT_PASSWORD) \
-e CONNECTION_METHOD=xpra \
-p $(RDP_PORT):3389 \
-p 10000:10000 \
-p $(METRICS_PORT):9118 \
$(DOCKER_PREFIX)capella/remote:$$(echo "$(DOCKER_TAG_SCHEMA)" | envsubst)

Expand Down Expand Up @@ -463,9 +465,13 @@ run-t4c/client/exporter: t4c/client/base
-e LOG_LEVEL="$(LOG_LEVEL)" \
$(DOCKER_PREFIX)t4c/client/base:$$(echo "$(DOCKER_TAG_SCHEMA)" | envsubst) export

debug-capella/base: DOCKER_RUN_FLAGS=-it --entrypoint="bash"
debug-capella/base: DOCKER_RUN_FLAGS=-it --entrypoint="bash" -p 10000:10000
debug-capella/base: run-capella/base

debug-capella/remote: DOCKER_RUN_FLAGS=-it -p 10001:10001
debug-capella/remote: run-capella/remote


debug-t4c/client/backup: LOG_LEVEL=DEBUG
debug-t4c/client/backup: DOCKER_RUN_FLAGS=-it --entrypoint="bash" -v $$(pwd)/backups/backup.py:/opt/capella/backup.py
debug-t4c/client/backup: run-t4c/client/backup
Expand Down
5 changes: 3 additions & 2 deletions base/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ENV SHELL=/bin/bash

RUN apt-get update && \
apt-get upgrade --yes && \
apt-get install --yes \
apt-get install --yes --no-install-recommends \
gettext-base \
locales \
python3 \
Expand All @@ -21,7 +21,8 @@ RUN apt-get update && \
git-lfs \
unzip \
neovim \
zip && \
zip \
wget && \
rm -rf /var/lib/apt/lists/*

RUN echo "en_GB.UTF-8 UTF-8" >> /etc/locale.gen && \
Expand Down
4 changes: 2 additions & 2 deletions capella/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ ONBUILD RUN if [ "$INJECT_PACKAGES" = "true" ]; then \
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 871920D1991BC93C; \
apt-get update; \
## Install the packages
apt-get install -y \
apt-get install -y --no-install-recommends \
libjavascriptcoregtk-4.0-18=2.28.1-1 \
libwebkit2gtk-4.0-37=2.28.1-1; \
rm /etc/apt/sources.list.d/focal.list; \
Expand All @@ -46,7 +46,7 @@ FROM base as old_gtk_false
ONBUILD USER root
ONBUILD COPY libs /tmp/libs
ONBUILD RUN apt-get update && \
apt-get install -y \
apt-get install -y --no-install-recommends \
libjavascriptcoregtk-4.0-18 \
libwebkit2gtk-4.0-37 && \
rm -rf /var/lib/apt/lists/*;
Expand Down
9 changes: 9 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
# SPDX-License-Identifier: Apache-2.0

install:
python -m venv .venv
.venv/bin/pip install -r requirements.txt

serve:
.venv/bin/mkdocs serve
2 changes: 1 addition & 1 deletion docs/docs/capella/base.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ If you're missing a dropin in the list, feel free to open a PR.
#### Optional: Workaround of pinned library versions to remove incompatibilities

**Note:**
_This workaround is normally handled in the [Dockerfile](capella/Dockerfile) and it is
_This workaround is normally handled in the Dockerfile and it is
only necessary to download below libraries if there are restrictions on your network
that block an access to these libraries when the Docker image is being built._

Expand Down
74 changes: 54 additions & 20 deletions docs/docs/remote.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The remote images allow to extend the
- T4C base image (`t4c/client/base`)
- Pure::variants image (`t4c/client/pure-variants`)

with a RDP server and a metrics endpoint to measure the container activity.
with a RDP or XPRA server and a metrics endpoint to measure the container activity.

It is a basic Linux server with a [Openbox](http://openbox.org/) installation.

Expand All @@ -21,6 +21,8 @@ It is a basic Linux server with a [Openbox](http://openbox.org/) installation.

#### Optional: Customize Openbox

!!! warning "Openbox is only used for the connection method RDP."

Feel free to adjust the configurations `remote/rc.xml` and `remote/menu.xml` to satisfy
custom Openbox configuration needs.

Expand All @@ -36,31 +38,63 @@ where `$BASE_IMAGE` is `capella/base`, `t4c/client/base` or `t4c/client/pure-var

## Run the container

```zsh
docker run -d \
-p $RDP_EXTERNAL_PORT:3389 \
-e RMT_PASSWORD=$RMT_PASSWORD \
$BASE_IMAGE/remote
```

Replace the followings variables:

- `$BASE_IMAGE` with `capella/base`, `t4c/client/base` or `t4c/client/pure-variants`. Please check the `In a remote container (RDP)` on the individual page of the base image for additional configuration options.
- `$RDP_EXTERNAL_PORT` to the external port for RDP on your host (usually `3389`)
- `$BASE_IMAGE` with `capella/base`, `t4c/client/base` or `t4c/client/pure-variants`. Please check the individual section `In a remote container (RDP)` of the individual base image documentation pages for additional configuration options.
- `$RMT_PASSWORD` is the password for remote connections (for the login via RDP) and has
to be at least 8 characters long.

After starting the container, you should be able to connect to
`localhost:$RDP_EXTERNAL_PORT` with your preferred RDP Client.
<!-- prettier-ignore-start -->
=== "Connect via RDP"

The container image contains a `xrdp` server. To use RDP to connect to the container, run the container with the following command:

```zsh
docker run -d \
-p $RDP_EXTERNAL_PORT:3389 \
-e CONNECTION_METHOD=rdp \
-e RMT_PASSWORD=$RMT_PASSWORD \
$BASE_IMAGE/remote
```

Replace `$RDP_EXTERNAL_PORT` with the external port that the RDP
server should listen on (usually `3389`).

After starting the container, you should be able to connect to
`localhost:$RDP_EXTERNAL_PORT` with your preferred RDP Client.

For the login use the followings credentials:

- **Username**: `techuser`
- **Password**: `$RMT_PASSWORD`

The screen size is set every time the connection is established. Depending on your
RDP client, you will also be able to set the preferred screen size in the settings.

By default, Remmina (RDP client for Linux) starts in a tiny window. To fix that, you can
easily set "Use client resolution" instead of "Use initial window size" in the remote
connection profile.


=== "Connect via XPRA"

The container image contains a `xpra-html5` server. To use XPRA via HTML5 to connect to the container, run the container with the following command:

For the login use the followings credentials:
```zsh
docker run -d \
-p $XPRA_EXTERNAL_PORT:10000 \
-e CONNECTION_METHOD=xpra \
-e RMT_PASSWORD=$RMT_PASSWORD \
$BASE_IMAGE/remote
```

- **Username**: `techuser`
- **Password**: `$RMT_PASSWORD`
Then, open a browser and connect to:
```
http://techuser:${RMT_PASSWORD}@localhost:${XPRA_EXTERNAL_PORT}?floating_menu=0
```

The screen size is set every time the connection is established. Depending on your
RDP client, you will also be able to set the preferred screen size in the settings.
More configuration options can be passed as query parameters.
See the [xpra-html5 documentation](https://github.com/Xpra-org/xpra-html5/blob/master/docs/Configuration.md)
for more information.

By default, Remmina (RDP client for Linux) starts in a tiny window. To fix that, you can
easily set "Use client resolution" instead of "Use initial window size" in the remote
connection profile.
<!-- prettier-ignore-end -->
2 changes: 2 additions & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ markdown_extensions:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
- pymdownx.tabbed:
alternate_style: true

extra:
generator: false
Expand Down
4 changes: 4 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
# SPDX-License-Identifier: CC0-1.0

mkdocs-material>=9.4.0
22 changes: 20 additions & 2 deletions remote/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
ARG BASE_IMAGE=capella/base
FROM ${BASE_IMAGE}

# Port if xrdp is used as connection method.
EXPOSE 3389

# Port if xpra is used as connection method.
EXPOSE 10000

ARG DEBIAN_FRONTEND=noninteractive

SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
Expand All @@ -12,7 +18,8 @@ ENV SHELL=/bin/bash
# Install RDP (XRDP with XORG)
USER root

RUN apt-get update && apt-get upgrade -y && apt-get install -y \
# Install xrdp and dependencies
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \
xrdp \
xserver-xorg-core \
xorgxrdp \
Expand All @@ -22,6 +29,11 @@ RUN apt-get update && apt-get upgrade -y && apt-get install -y \
xprintidle \
nitrogen && rm -rf /var/lib/apt/lists/*

# Install xpra and dependencies
RUN wget -O /usr/share/keyrings/xpra.asc https://xpra.org/xpra.asc && \
wget -O /etc/apt/sources.list.d/xpra.sources https://raw.githubusercontent.com/Xpra-org/xpra/master/packaging/repos/bookworm/xpra.sources && \
apt-get update && apt-get install -y --no-install-recommends xpra xpra-x11 xpra-html5 apache2-utils nginx && rm -rf /var/lib/apt/lists/*

COPY rc.xml /etc/xdg/openbox/rc.xml
COPY menu.xml /etc/xdg/openbox/menu.xml

Expand All @@ -32,6 +44,10 @@ COPY bg-saved.cfg /home/techuser/.config/nitrogen/bg-saved.cfg
# Copy Supervisor Configuration
RUN pip install --no-cache-dir supervisor==4.2.5
COPY supervisord.conf /etc/supervisord.conf
COPY supervisord.*.conf /tmp/supervisord/

# Copy nginx configuration for xpra
COPY nginx.conf /etc/nginx/nginx.conf

# Allow any user to start the RDP server
# Depending on the base image used, Xwrapper.config may (not) be available and has to be created.
Expand All @@ -42,7 +58,9 @@ RUN sed -i 's/allowed_users=console/allowed_users=anybody/g' /etc/X11/Xwrapper.c
# Set permissions
RUN mkdir -p /run/xrdp/sockdir && \
chown -R techuser /etc/xrdp /run/xrdp /var/log/xrdp* && \
chown techuser /var/log
chown techuser /var/log && \
chown techuser /etc/supervisord.conf /var/log/nginx /var/log/nginx/* && \
chown techuser /etc/nginx

WORKDIR /home/techuser

Expand Down
32 changes: 32 additions & 0 deletions remote/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
# SPDX-License-Identifier: Apache-2.0

pid /tmp/nginx.pid;
daemon off;
events{}
http {
# These options are needed to run as non-root
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;

server {
listen 10000;
server_name _;

location / {
auth_basic "Session access";
auth_basic_user_file /etc/nginx/.htpasswd;

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;

proxy_pass http://127.0.0.1:10001;
proxy_buffering off;
}
}
}
12 changes: 12 additions & 0 deletions remote/startup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ else
exit 1;
fi

echo "${RMT_PASSWORD:?}" | htpasswd -ci /etc/nginx/.htpasswd techuser

unset RMT_PASSWORD

# Run preparation scripts
Expand All @@ -31,4 +33,14 @@ for filename in /opt/setup/*.sh; do
/bin/bash $filename
done

# Load supervisord configuration for connection method
SUPERVISORD_CONFIG_PATH=/tmp/supervisord/supervisord.$CONNECTION_METHOD.conf
if [ -f "$SUPERVISORD_CONFIG_PATH" ]; then
echo "Adding '$SUPERVISORD_CONFIG_PATH' to configuration."
cat $SUPERVISORD_CONFIG_PATH >> /etc/supervisord.conf
else
echo "No '$SUPERVISORD_CONFIG_PATH' found'. Falling back to xrdp configuration."
cat /tmp/supervisord/supervisord.xrdp.conf >> /etc/supervisord.conf
fi

exec supervisord
11 changes: 0 additions & 11 deletions remote/supervisord.conf
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
# SPDX-License-Identifier: Apache-2.0

[program:xrdp]
command=/usr/sbin/xrdp --nodaemon
user=techuser
autorestart=true

[program:xrdp-sesman]
command=/usr/sbin/xrdp-sesman --nodaemon
user=techuser
autorestart=true
environment=DISPLAY=":10"

[program:idletime]
; Return idle time of xserver in seconds from xprintidle
command=python .metrics.py
Expand Down
13 changes: 13 additions & 0 deletions remote/supervisord.xpra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
# SPDX-License-Identifier: Apache-2.0

[program:xpra]
command=xpra start --start=/home/techuser/.config/openbox/autostart --attach=yes --daemon=no --bind-tcp=0.0.0.0:10001
user=techuser
autorestart=true
environment=DISPLAY=":0"

[program:nginx]
command=nginx
user=techuser
autorestart=true
13 changes: 13 additions & 0 deletions remote/supervisord.xrdp.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
# SPDX-License-Identifier: Apache-2.0

[program:xrdp]
command=/usr/sbin/xrdp --nodaemon
user=techuser
autorestart=true

[program:xrdp-sesman]
command=/usr/sbin/xrdp-sesman --nodaemon
user=techuser
autorestart=true
environment=DISPLAY=":10"

0 comments on commit 8f076c4

Please sign in to comment.