# Runtime container for JS8Call with X11 and audio support FROM ubuntu:24.04 ENV DEBIAN_FRONTEND=noninteractive # Install runtime dependencies RUN apt-get update && apt-get install -y \ # X11 support x11-apps \ x11-utils \ libx11-6 \ libxext6 \ libxrender1 \ libxtst6 \ libxi6 \ libxrandr2 \ libxcursor1 \ libxinerama1 \ libxkbcommon-x11-0 \ # Qt6 runtime dependencies qt6-base-dev \ libqt6core6 \ libqt6gui6 \ libqt6widgets6 \ libqt6multimedia6 \ libqt6serialport6 \ libqt6svg6 \ libqt6opengl6 \ # Audio support (PulseAudio and ALSA) pulseaudio \ pulseaudio-utils \ alsa-utils \ libasound2t64 \ libpulse0 \ # Other runtime dependencies libfftw3-single3 \ libusb-1.0-0 \ libudev1 \ libboost-filesystem1.83.0 \ libboost-thread1.83.0 \ libboost-system1.83.0 \ # Utilities wget \ ca-certificates \ file \ && rm -rf /var/lib/apt/lists/* # Create a non-root user for running the application # Try to use UID 1000 for PulseAudio compatibility, but use next available if taken RUN if ! id -u 1000 >/dev/null 2>&1; then \ useradd -m -s /bin/bash -u 1000 js8call; \ else \ useradd -m -s /bin/bash js8call; \ fi && \ mkdir -p /home/js8call/.config && \ chown -R js8call:js8call /home/js8call && \ usermod -a -G audio,video js8call # Create config directory RUN mkdir -p /home/js8call/.config && \ chown -R js8call:js8call /home/js8call/.config # Create directory for the extracted application RUN mkdir -p /opt/js8call && \ chown js8call:js8call /opt/js8call # Set up environment for Qt and audio ENV QT_X11_NO_MITSHM=1 ENV ALSA_CARD=0 # Create entrypoint script RUN echo '#!/bin/bash' > /opt/js8call/entrypoint.sh && \ echo 'set -e' >> /opt/js8call/entrypoint.sh && \ echo '' >> /opt/js8call/entrypoint.sh && \ echo '# Check if AppImage exists' >> /opt/js8call/entrypoint.sh && \ echo 'if [ ! -f /tmp/js8call.AppImage ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' echo "Error: JS8Call AppImage not found at /tmp/js8call.AppImage"' >> /opt/js8call/entrypoint.sh && \ echo ' echo "Please mount the AppImage to the container"' >> /opt/js8call/entrypoint.sh && \ echo ' exit 1' >> /opt/js8call/entrypoint.sh && \ echo 'fi' >> /opt/js8call/entrypoint.sh && \ echo '' >> /opt/js8call/entrypoint.sh && \ echo '# Check if we need to extract' >> /opt/js8call/entrypoint.sh && \ echo 'if [ ! -f /opt/js8call/extracted/AppRun ] && [ ! -f /opt/js8call/extracted/js8call ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' echo "Extracting AppImage..."' >> /opt/js8call/entrypoint.sh && \ echo ' cd /opt/js8call' >> /opt/js8call/entrypoint.sh && \ echo ' # Make AppImage executable first' >> /opt/js8call/entrypoint.sh && \ echo ' cp /tmp/js8call.AppImage /tmp/js8call-exec.AppImage' >> /opt/js8call/entrypoint.sh && \ echo ' chmod +x /tmp/js8call-exec.AppImage' >> /opt/js8call/entrypoint.sh && \ echo ' # Extract the AppImage' >> /opt/js8call/entrypoint.sh && \ echo ' /tmp/js8call-exec.AppImage --appimage-extract > /dev/null 2>&1 || {' >> /opt/js8call/entrypoint.sh && \ echo ' echo "Standard extraction failed, trying manual extraction..."' >> /opt/js8call/entrypoint.sh && \ echo ' mkdir -p /opt/js8call/extracted' >> /opt/js8call/entrypoint.sh && \ echo ' cd /opt/js8call/extracted' >> /opt/js8call/entrypoint.sh && \ echo ' unsquashfs -f -d . /tmp/js8call-exec.AppImage || {' >> /opt/js8call/entrypoint.sh && \ echo ' echo "Failed to extract AppImage"' >> /opt/js8call/entrypoint.sh && \ echo ' exit 1' >> /opt/js8call/entrypoint.sh && \ echo ' }' >> /opt/js8call/entrypoint.sh && \ echo ' }' >> /opt/js8call/entrypoint.sh && \ echo ' # Move extracted contents if needed' >> /opt/js8call/entrypoint.sh && \ echo ' if [ -d /opt/js8call/squashfs-root ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' mv /opt/js8call/squashfs-root /opt/js8call/extracted' >> /opt/js8call/entrypoint.sh && \ echo ' fi' >> /opt/js8call/entrypoint.sh && \ echo ' rm -f /tmp/js8call-exec.AppImage' >> /opt/js8call/entrypoint.sh && \ echo 'fi' >> /opt/js8call/entrypoint.sh && \ echo '' >> /opt/js8call/entrypoint.sh && \ echo '# Find the executable' >> /opt/js8call/entrypoint.sh && \ echo 'if [ -f /opt/js8call/extracted/AppRun ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' EXEC_PATH="/opt/js8call/extracted/AppRun"' >> /opt/js8call/entrypoint.sh && \ echo 'elif [ -f /opt/js8call/extracted/js8call ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' EXEC_PATH="/opt/js8call/extracted/js8call"' >> /opt/js8call/entrypoint.sh && \ echo 'elif [ -f /opt/js8call/extracted/usr/bin/js8call ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' EXEC_PATH="/opt/js8call/extracted/usr/bin/js8call"' >> /opt/js8call/entrypoint.sh && \ echo 'else' >> /opt/js8call/entrypoint.sh && \ echo ' EXEC_PATH=$(find /opt/js8call/extracted -name "js8call" -type f -executable | head -1)' >> /opt/js8call/entrypoint.sh && \ echo ' if [ -z "$EXEC_PATH" ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' echo "Could not find js8call executable in extracted AppImage"' >> /opt/js8call/entrypoint.sh && \ echo ' ls -la /opt/js8call/extracted/' >> /opt/js8call/entrypoint.sh && \ echo ' exit 1' >> /opt/js8call/entrypoint.sh && \ echo ' fi' >> /opt/js8call/entrypoint.sh && \ echo 'fi' >> /opt/js8call/entrypoint.sh && \ echo '' >> /opt/js8call/entrypoint.sh && \ echo '# Copy existing config if mounted' >> /opt/js8call/entrypoint.sh && \ echo 'if [ -d /tmp/js8call-config ] && [ -f /tmp/js8call-config/JS8Call.ini ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' echo "Loading existing configuration..."' >> /opt/js8call/entrypoint.sh && \ echo ' mkdir -p /home/js8call/.config' >> /opt/js8call/entrypoint.sh && \ echo ' cp /tmp/js8call-config/JS8Call.ini /home/js8call/.config/JS8Call.ini' >> /opt/js8call/entrypoint.sh && \ echo 'fi' >> /opt/js8call/entrypoint.sh && \ echo '' >> /opt/js8call/entrypoint.sh && \ echo '# Launch JS8Call from extracted directory' >> /opt/js8call/entrypoint.sh && \ echo 'echo "Starting JS8Call from $EXEC_PATH..."' >> /opt/js8call/entrypoint.sh && \ echo 'cd /opt/js8call/extracted' >> /opt/js8call/entrypoint.sh && \ echo '"$EXEC_PATH" "$@"' >> /opt/js8call/entrypoint.sh && \ echo 'EXIT_CODE=$?' >> /opt/js8call/entrypoint.sh && \ echo '' >> /opt/js8call/entrypoint.sh && \ echo '# Copy config file back if mounted' >> /opt/js8call/entrypoint.sh && \ echo 'if [ -d /tmp/js8call-config ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' if [ -f /home/js8call/.config/JS8Call.ini ]; then' >> /opt/js8call/entrypoint.sh && \ echo ' echo "Saving configuration..."' >> /opt/js8call/entrypoint.sh && \ echo ' cp /home/js8call/.config/JS8Call.ini /tmp/js8call-config/JS8Call.ini' >> /opt/js8call/entrypoint.sh && \ echo ' fi' >> /opt/js8call/entrypoint.sh && \ echo 'fi' >> /opt/js8call/entrypoint.sh && \ echo '' >> /opt/js8call/entrypoint.sh && \ echo 'exit $EXIT_CODE' >> /opt/js8call/entrypoint.sh RUN chmod +x /opt/js8call/entrypoint.sh && \ chown js8call:js8call /opt/js8call/entrypoint.sh # Install squashfs-tools for extraction RUN apt-get update && apt-get install -y squashfs-tools && rm -rf /var/lib/apt/lists/* # Make sure js8call user can access X11 RUN mkdir -p /tmp/.X11-unix && chmod 1777 /tmp/.X11-unix # Make home directory writable by any user RUN chmod -R 777 /home/js8call && \ mkdir -p /home/js8call/.local/share && \ chmod -R 777 /home/js8call/.local # Switch to non-root user USER js8call WORKDIR /home/js8call # Default command CMD ["/opt/js8call/entrypoint.sh"]