diff --git a/.dockerignore b/.dockerignore index 05e5f58..dcc01a8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -21,6 +21,7 @@ **/*.log **/console/cert.pem* **/dhcpd.* +webvirtcloud/settings.py # IDEs and OS **/.idea diff --git a/Dockerfile b/Dockerfile index 28a568e..d1ce88d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,6 @@ EXPOSE 6080 # Use baseimage-docker's init system. CMD ["/sbin/my_init"] - RUN echo 'APT::Get::Clean=always;' >> /etc/apt/apt.conf.d/99AutomaticClean RUN apt-get update -qqy \ @@ -14,8 +13,10 @@ RUN apt-get update -qqy \ --no-install-recommends \ git \ python3-venv \ + python3-pip \ python3-dev \ python3-lxml \ + python3-libvirt \ libvirt-dev \ zlib1g-dev \ nginx \ @@ -30,42 +31,53 @@ RUN apt-get update -qqy \ # Setup webvirtcloud WORKDIR /srv/webvirtcloud -# Install Python dependencies first to leverage Docker layer caching +# Install Python dependencies first with system-site-packages to leverage prebuilt bindings COPY conf/requirements.txt conf/requirements.txt -RUN python3 -m venv venv && \ +RUN python3 -m venv --system-site-packages venv && \ . venv/bin/activate && \ - pip3 install -U pip && \ - pip3 install wheel && \ + pip3 install -U pip wheel && \ pip3 install -r conf/requirements.txt && \ pip3 cache purge # Copy application source COPY . /srv/webvirtcloud +# Setup build-time settings, run collectstatic, and set permissions RUN . venv/bin/activate && \ - python3 manage.py makemigrations && \ - python3 manage.py migrate && \ + if [ ! -f webvirtcloud/settings.py ]; then \ + cp webvirtcloud/settings.py.template webvirtcloud/settings.py && \ + python3 -c 'import secrets; print(secrets.token_urlsafe(50))' > /tmp/secret_key && \ + sed -i "s|^SECRET_KEY = .*|SECRET_KEY = \"$(cat /tmp/secret_key)\"|" webvirtcloud/settings.py && \ + rm -f /tmp/secret_key; \ + fi && \ python3 manage.py collectstatic --noinput && \ chown -R www-data:www-data /srv/webvirtcloud # Setup Nginx RUN printf "\n%s" "daemon off;" >> /etc/nginx/nginx.conf && \ - rm /etc/nginx/sites-enabled/default && \ + rm -f /etc/nginx/sites-enabled/default && \ chown -R www-data:www-data /var/lib/nginx COPY conf/nginx/webvirtcloud.conf /etc/nginx/conf.d/ -# Register services to runit -RUN mkdir /etc/service/nginx && \ - mkdir /etc/service/nginx-log-forwarder && \ - mkdir /etc/service/webvirtcloud && \ - mkdir /etc/service/novnc +# Register startup init script and services to runit +RUN mkdir -p /etc/my_init.d \ + /etc/service/nginx \ + /etc/service/nginx-log-forwarder \ + /etc/service/webvirtcloud \ + /etc/service/novnc +COPY conf/runit/10_webvirtcloud_init.sh /etc/my_init.d/10_webvirtcloud_init.sh COPY conf/runit/nginx /etc/service/nginx/run COPY conf/runit/nginx-log-forwarder /etc/service/nginx-log-forwarder/run COPY conf/runit/novncd.sh /etc/service/novnc/run COPY conf/runit/webvirtcloud.sh /etc/service/webvirtcloud/run +RUN chmod +x /etc/my_init.d/10_webvirtcloud_init.sh \ + /etc/service/nginx/run \ + /etc/service/nginx-log-forwarder/run \ + /etc/service/novnc/run \ + /etc/service/webvirtcloud/run -# Define mountable directories. -#VOLUME [] +# Declare mountable data directory for persistent SQLite and SSH keys +VOLUME ["/srv/webvirtcloud/data", "/var/www/.ssh"] WORKDIR /srv/webvirtcloud diff --git a/README.md b/README.md index 36f876a..7cfdfc7 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,21 @@ chmod 744 install.sh ./install.sh ``` +## Docker Deployment (Docker Compose) + +Run WebVirtCloud in a container with persistent volumes for data and SSH keys: + +```bash +# 1. Clone repository: +git clone https://github.com/retspen/webvirtcloud +cd webvirtcloud + +# 2. Start services: +docker compose up -d +``` + +Access the panel at `http://` and noVNC console at port `6080`. + ## Manual Installation ### Generate secret key diff --git a/conf/runit/10_webvirtcloud_init.sh b/conf/runit/10_webvirtcloud_init.sh new file mode 100755 index 0000000..9502525 --- /dev/null +++ b/conf/runit/10_webvirtcloud_init.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -e + +APP_DIR="/srv/webvirtcloud" +DATA_DIR="$APP_DIR/data" +mkdir -p "$DATA_DIR" "/var/www/.ssh" + +# If settings.py doesn't exist, generate from template +if [ ! -f "$APP_DIR/webvirtcloud/settings.py" ]; then + echo "* Generating webvirtcloud/settings.py from template..." + cp "$APP_DIR/webvirtcloud/settings.py.template" "$APP_DIR/webvirtcloud/settings.py" +fi + +# Set SECRET_KEY if placeholder exists +if grep -q 'SECRET_KEY = ""' "$APP_DIR/webvirtcloud/settings.py" || grep -q "SECRET_KEY = ''" "$APP_DIR/webvirtcloud/settings.py"; then + KEY="${SECRET_KEY:-$("$APP_DIR/venv/bin/python3" -c 'import secrets; print(secrets.token_urlsafe(50))')}" + sed -i "s|^SECRET_KEY = .*|SECRET_KEY = \"${KEY}\"|" "$APP_DIR/webvirtcloud/settings.py" +fi + +# Configure CSRF_TRUSTED_ORIGINS if environment variable is set +if [ -n "$CSRF_TRUSTED_ORIGINS" ]; then + echo "* Setting CSRF_TRUSTED_ORIGINS from environment..." + origins="" + IFS=',' read -ra ADDR <<< "$CSRF_TRUSTED_ORIGINS" + for o in "${ADDR[@]}"; do + clean_o=$(echo "$o" | xargs) + [ -n "$clean_o" ] && origins="${origins}'${clean_o}', " + done + sed -i "s|^CSRF_TRUSTED_ORIGINS = .*|CSRF_TRUSTED_ORIGINS = [ ${origins} ]|" "$APP_DIR/webvirtcloud/settings.py" +fi + +# Persist SQLite database in DATA_DIR +if [ ! -f "$DATA_DIR/db.sqlite3" ] && [ -f "$APP_DIR/db.sqlite3" ] && [ ! -L "$APP_DIR/db.sqlite3" ]; then + mv "$APP_DIR/db.sqlite3" "$DATA_DIR/db.sqlite3" +fi +touch "$DATA_DIR/db.sqlite3" +ln -sf "$DATA_DIR/db.sqlite3" "$APP_DIR/db.sqlite3" + +# Run database migrations +echo "* Running database migrations..." +"$APP_DIR/venv/bin/python3" "$APP_DIR/manage.py" migrate --noinput + +# Set proper permissions on runtime and data directories +chown -R www-data:www-data "$DATA_DIR" "/var/www/.ssh" +chown www-data:www-data "$APP_DIR/webvirtcloud/settings.py" 2>/dev/null || true +chmod 700 "/var/www/.ssh" 2>/dev/null || true diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0cc0764 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +services: + webvirtcloud: + build: + context: . + dockerfile: Dockerfile + image: webvirtcloud:latest + container_name: webvirtcloud + restart: unless-stopped + ports: + - "80:80" + - "6080:6080" + environment: + # Optional: custom Django secret key. If unset, automatically generated at first launch. + # - SECRET_KEY=your-custom-secret-key-here + # Optional: comma-separated trusted CSRF origins (e.g. http://wvc.example.com,https://wvc.example.com) + # - CSRF_TRUSTED_ORIGINS=http://localhost,http://127.0.0.1 + - TZ=UTC + volumes: + # Persistent SQLite database and runtime data + - webvirtcloud-data:/srv/webvirtcloud/data + # Persistent SSH keys for compute node authentication + - webvirtcloud-ssh:/var/www/.ssh + +volumes: + webvirtcloud-data: + driver: local + webvirtcloud-ssh: + driver: local