diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..faaba34 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,21 @@ +# Source control +.git +.gitignore +.github +.github/** +Dockerfile* +resources/ + +# Node dependencies +node_modules/ + +# Logs and temp files +*.log +tmp/ + +# Local env settings +.env + +# IDE/project files +.vscode/ +.DS_Store \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index d50ee95..d666fad 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ public/api.html linguist-documentation -public/openapi.json linguist-documentation \ No newline at end of file +public/openapi.json linguist-documentation +resources/ export-ignore +.github/ export-ignore \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 275f72f..4e07c80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,14 @@ - Updated `AdminModel` & `AdminController` to persist and validate new settings - Enhanced `shareFolder()` view to pull from admin config and format the max‑upload‑size label - Restored the MIT license copyright line that was inadvertently removed. +- Move .htaccess to public folder this was mistake since API refactor. +- gitattributes to ignore resources/ & .github/ on export +- Hardened `Dockerfile` permissions: all code files owned by `root:www-data` (dirs `755`, files `644`), only `uploads/`, `users/` and `metadata/` are writable by `www-data` (`775`) +- `.dockerignore` entry to exclude the `.github` directory from build context +- `start.sh`: + - Creates and secures `metadata/log` for Apache logs + - Dynamically creates and sets permissions on `uploads`, `users`, and `metadata` directories at startup +- Apache VirtualHost updated to redirect `ErrorLog` and `CustomLog` into `/var/www/metadata/log` --- diff --git a/Dockerfile b/Dockerfile index edfabef..35f79a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,12 +6,9 @@ FROM ubuntu:24.04 AS appsource RUN apt-get update && \ apt-get install -y --no-install-recommends ca-certificates && \ - rm -rf /var/lib/apt/lists/* + rm -rf /var/lib/apt/lists/* # clean up apt cache -# prepare the folder and remove Apache’s default index RUN mkdir -p /var/www && rm -f /var/www/html/index.html - -# **Copy the FileRise source** (where your composer.json lives) COPY . /var/www ############################# @@ -19,76 +16,53 @@ COPY . /var/www ############################# FROM composer:2 AS composer WORKDIR /app - -# **Copy composer files from the source** and install COPY --from=appsource /var/www/composer.json /var/www/composer.lock ./ -RUN composer install --no-dev --optimize-autoloader +RUN composer install --no-dev --optimize-autoloader # production-ready autoloader ############################# # Final Stage – runtime image ############################# FROM ubuntu:24.04 - LABEL by=error311 -# Set basic environment variables (these can be overridden via the Unraid template) ENV DEBIAN_FRONTEND=noninteractive \ HOME=/root \ - LC_ALL=C.UTF-8 \ - LANG=en_US.UTF-8 \ - LANGUAGE=en_US.UTF-8 \ - TERM=xterm \ - UPLOAD_MAX_FILESIZE=5G \ - POST_MAX_SIZE=5G \ - TOTAL_UPLOAD_SIZE=5G \ + LC_ALL=C.UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 TERM=xterm \ + UPLOAD_MAX_FILESIZE=5G POST_MAX_SIZE=5G TOTAL_UPLOAD_SIZE=5G \ PERSISTENT_TOKENS_KEY=default_please_change_this_key \ - PUID=99 \ - PGID=100 + PUID=99 PGID=100 # Install Apache, PHP, and required extensions RUN apt-get update && \ apt-get upgrade -y && \ apt-get install -y --no-install-recommends \ - apache2 \ - php \ - php-json \ - php-curl \ - php-zip \ - php-mbstring \ - php-gd \ - php-xml \ - ca-certificates \ - curl \ - git \ - openssl && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* + apache2 php php-json php-curl php-zip php-mbstring php-gd php-xml \ + ca-certificates curl git openssl && \ + apt-get clean && rm -rf /var/lib/apt/lists/* # slim down image -# Remap www-data to the PUID/PGID provided +# Remap www-data to the PUID/PGID provided for safe bind mounts RUN set -eux; \ - # only change the UID if it’s not already correct - if [ "$(id -u www-data)" != "${PUID}" ]; then \ - usermod -u "${PUID}" www-data; \ - fi; \ - # attempt to change the GID, but ignore “already exists” errors - if [ "$(id -g www-data)" != "${PGID}" ]; then \ - groupmod -g "${PGID}" www-data 2>/dev/null || true; \ - fi; \ - # finally set www-data’s primary group to PGID (will succeed if the group exists) + if [ "$(id -u www-data)" != "${PUID}" ]; then usermod -u "${PUID}" www-data; fi; \ + if [ "$(id -g www-data)" != "${PGID}" ]; then groupmod -g "${PGID}" www-data 2>/dev/null || true; fi; \ usermod -g "${PGID}" www-data -# Copy application tuning and code +# Copy config, code, and vendor COPY custom-php.ini /etc/php/8.3/apache2/conf.d/99-app-tuning.ini COPY --from=appsource /var/www /var/www -COPY --from=composer /app/vendor /var/www/vendor +COPY --from=composer /app/vendor /var/www/vendor -# Ensure the webroot is owned by the remapped www-data user -RUN chown -R www-data:www-data /var/www && chmod -R 775 /var/www +# Secure permissions: code read-only, only data dirs writable +RUN chown -R root:www-data /var/www && \ + find /var/www -type d -exec chmod 755 {} \; && \ + find /var/www -type f -exec chmod 644 {} \; && \ + mkdir -p /var/www/public/uploads /var/www/users /var/www/metadata && \ + chown -R www-data:www-data /var/www/public/uploads /var/www/users /var/www/metadata && \ + chmod -R 775 /var/www/public/uploads /var/www/users /var/www/metadata # writable upload areas -# Create a symlink for uploads folder in public directory. +# Preserve your uploads symlink RUN cd /var/www/public && ln -s ../uploads uploads -# Configure Apache +# Apache site configuration RUN cat <<'EOF' > /etc/apache2/sites-available/000-default.conf ServerAdmin webmaster@localhost @@ -96,17 +70,16 @@ RUN cat <<'EOF' > /etc/apache2/sites-available/000-default.conf AllowOverride All Require all granted - DirectoryIndex index.php index.html + DirectoryIndex index.html - ErrorLog /var/log/apache2/error.log - CustomLog /var/log/apache2/access.log combined + ErrorLog /var/www/metadata/log/error.log + CustomLog /var/www/metadata/log/access.log combined EOF -# Enable the rewrite and headers modules +# Enable required modules RUN a2enmod rewrite headers -# Expose ports and set up the startup script EXPOSE 80 443 COPY start.sh /usr/local/bin/start.sh RUN chmod +x /usr/local/bin/start.sh diff --git a/.htaccess b/public/.htaccess similarity index 100% rename from .htaccess rename to public/.htaccess diff --git a/start.sh b/start.sh index 12b6b51..b2fe67f 100644 --- a/start.sh +++ b/start.sh @@ -1,162 +1,108 @@ #!/bin/bash - +set -euo pipefail echo "🚀 Running start.sh..." -# Warn if default persistent tokens key is in use -if [ "$PERSISTENT_TOKENS_KEY" = "default_please_change_this_key" ]; then - echo "⚠️ WARNING: Using default persistent tokens key. Please override PERSISTENT_TOKENS_KEY for production." +# 1) Token‐key warning +if [ "${PERSISTENT_TOKENS_KEY}" = "default_please_change_this_key" ]; then + echo "⚠️ WARNING: Using default persistent tokens key—override for production." fi -# Update config.php based on environment variables +# 2) Update config.php based on environment variables CONFIG_FILE="/var/www/config/config.php" -if [ -f "$CONFIG_FILE" ]; then - echo "🔄 Updating config.php based on environment variables..." - if [ -n "$TIMEZONE" ]; then - echo " Setting TIMEZONE to $TIMEZONE" - sed -i "s|define('TIMEZONE',[[:space:]]*'[^']*');|define('TIMEZONE', '$TIMEZONE');|" "$CONFIG_FILE" - fi - if [ -n "$DATE_TIME_FORMAT" ]; then - echo "🔄 Setting DATE_TIME_FORMAT to $DATE_TIME_FORMAT" - sed -i "s|define('DATE_TIME_FORMAT',[[:space:]]*'[^']*');|define('DATE_TIME_FORMAT', '$DATE_TIME_FORMAT');|" "$CONFIG_FILE" - fi - if [ -n "$TOTAL_UPLOAD_SIZE" ]; then - echo "🔄 Setting TOTAL_UPLOAD_SIZE to $TOTAL_UPLOAD_SIZE" - sed -i "s|define('TOTAL_UPLOAD_SIZE',[[:space:]]*'[^']*');|define('TOTAL_UPLOAD_SIZE', '$TOTAL_UPLOAD_SIZE');|" "$CONFIG_FILE" - fi - if [ -n "$SECURE" ]; then - echo "🔄 Setting SECURE to $SECURE" - sed -i "s|\$envSecure = getenv('SECURE');|\$envSecure = '$SECURE';|" "$CONFIG_FILE" - fi - if [ -n "$SHARE_URL" ]; then - echo "🔄 Setting SHARE_URL to $SHARE_URL" - sed -i "s|define('SHARE_URL',[[:space:]]*'[^']*');|define('SHARE_URL', '$SHARE_URL');|" "$CONFIG_FILE" +if [ -f "${CONFIG_FILE}" ]; then + echo "🔄 Updating config.php from env vars..." + [ -n "${TIMEZONE:-}" ] && sed -i "s|define('TIMEZONE',[[:space:]]*'[^']*');|define('TIMEZONE', '${TIMEZONE}');|" "${CONFIG_FILE}" + [ -n "${DATE_TIME_FORMAT:-}" ] && sed -i "s|define('DATE_TIME_FORMAT',[[:space:]]*'[^']*');|define('DATE_TIME_FORMAT', '${DATE_TIME_FORMAT}');|" "${CONFIG_FILE}" + if [ -n "${TOTAL_UPLOAD_SIZE:-}" ]; then + sed -i "s|define('TOTAL_UPLOAD_SIZE',[[:space:]]*'[^']*');|define('TOTAL_UPLOAD_SIZE', '${TOTAL_UPLOAD_SIZE}');|" "${CONFIG_FILE}" fi + [ -n "${SECURE:-}" ] && sed -i "s|\$envSecure = getenv('SECURE');|\$envSecure = '${SECURE}';|" "${CONFIG_FILE}" + [ -n "${SHARE_URL:-}" ] && sed -i "s|define('SHARE_URL',[[:space:]]*'[^']*');|define('SHARE_URL', '${SHARE_URL}');|" "${CONFIG_FILE}" fi -# Ensure the PHP configuration directory exists +# 2.1) Prepare metadata/log for Apache logs +mkdir -p /var/www/metadata/log +chown www-data:www-data /var/www/metadata/log +chmod 775 /var/www/metadata/log + +# 2.2) Prepare other dynamic dirs +for d in uploads users metadata; do + tgt="/var/www/${d}" + mkdir -p "${tgt}" + chown www-data:www-data "${tgt}" + chmod 775 "${tgt}" +done + +# 3) Ensure PHP config dir & set upload limits mkdir -p /etc/php/8.3/apache2/conf.d - -# Update PHP upload limits at runtime if TOTAL_UPLOAD_SIZE is set. -if [ -n "$TOTAL_UPLOAD_SIZE" ]; then - echo "🔄 Updating PHP upload limits with TOTAL_UPLOAD_SIZE=$TOTAL_UPLOAD_SIZE" - echo "upload_max_filesize = $TOTAL_UPLOAD_SIZE" > /etc/php/8.3/apache2/conf.d/99-custom.ini - echo "post_max_size = $TOTAL_UPLOAD_SIZE" >> /etc/php/8.3/apache2/conf.d/99-custom.ini +if [ -n "${TOTAL_UPLOAD_SIZE:-}" ]; then + echo "🔄 Setting PHP upload limits to ${TOTAL_UPLOAD_SIZE}" + cat > /etc/php/8.3/apache2/conf.d/99-custom.ini < /etc/apache2/conf-enabled/limit_request_body.conf + LIMIT_REQUEST_BODY=$(( num * factor )) + echo "🔄 Setting Apache LimitRequestBody to ${LIMIT_REQUEST_BODY} bytes" + cat > /etc/apache2/conf-enabled/limit_request_body.conf < - LimitRequestBody $LIMIT_REQUEST_BODY + LimitRequestBody ${LIMIT_REQUEST_BODY} EOF fi -# Set Apache Timeout (default is 300 seconds) -echo "🔄 Setting Apache Timeout to 600 seconds" -cat < /etc/apache2/conf-enabled/timeout.conf +# 5) Configure Apache timeout (600s) +cat > /etc/apache2/conf-enabled/timeout.conf <//" /etc/apache2/sites-available/000-default.conf +# 6) Override ports if provided +if [ -n "${HTTP_PORT:-}" ]; then + sed -i "s/^Listen 80$/Listen ${HTTP_PORT}/" /etc/apache2/ports.conf + sed -i "s///" /etc/apache2/sites-available/000-default.conf +fi +if [ -n "${HTTPS_PORT:-}" ]; then + sed -i "s/^Listen 443$/Listen ${HTTPS_PORT}/" /etc/apache2/ports.conf fi -if [ -n "$HTTPS_PORT" ]; then - echo "🔄 Setting Apache HTTPS port to $HTTPS_PORT" - sed -i "s/^Listen 443$/Listen $HTTPS_PORT/" /etc/apache2/ports.conf -fi - -# Update Apache ServerName if environment variable is provided -if [ -n "$SERVER_NAME" ]; then - echo "🔄 Setting Apache ServerName to $SERVER_NAME" - echo "ServerName $SERVER_NAME" >> /etc/apache2/apache2.conf +# 7) Set ServerName +if [ -n "${SERVER_NAME:-}" ]; then + echo "ServerName ${SERVER_NAME}" >> /etc/apache2/apache2.conf else - echo "🔄 Setting Apache ServerName to default: FileRise" echo "ServerName FileRise" >> /etc/apache2/apache2.conf fi -echo "Final /etc/apache2/ports.conf content:" -cat /etc/apache2/ports.conf +# 8) Prepare dynamic data directories with least privilege +for d in uploads users metadata; do + tgt="/var/www/${d}" + mkdir -p "${tgt}" + chown www-data:www-data "${tgt}" + chmod 775 "${tgt}" +done -echo "📁 Web app is served from /var/www/public." - -# Ensure the uploads folder exists in /var/www -mkdir -p /var/www/uploads -echo "🔑 Fixing permissions for /var/www/uploads..." -chown -R ${PUID:-99}:${PGID:-100} /var/www/uploads -chmod -R 775 /var/www/uploads - -# Ensure the users folder exists in /var/www -mkdir -p /var/www/users -echo "🔑 Fixing permissions for /var/www/users..." -chown -R ${PUID:-99}:${PGID:-100} /var/www/users -chmod -R 775 /var/www/users - -# Ensure the metadata folder exists in /var/www -mkdir -p /var/www/metadata -echo "🔑 Fixing permissions for /var/www/metadata..." -chown -R ${PUID:-99}:${PGID:-100} /var/www/metadata -chmod -R 775 /var/www/metadata - -# Create users.txt only if it doesn't already exist (preserving persistent data) +# 9) Initialize persistent files if absent if [ ! -f /var/www/users/users.txt ]; then - echo "ℹ️ users.txt not found in persistent storage; creating new file..." echo "" > /var/www/users/users.txt - chown ${PUID:-99}:${PGID:-100} /var/www/users/users.txt + chown www-data:www-data /var/www/users/users.txt chmod 664 /var/www/users/users.txt -else - echo "ℹ️ users.txt already exists; preserving persistent data." fi -# Create createdTags.json only if it doesn't already exist (preserving persistent data) if [ ! -f /var/www/metadata/createdTags.json ]; then - echo "ℹ️ createdTags.json not found in persistent storage; creating new file..." echo "[]" > /var/www/metadata/createdTags.json - chown ${PUID:-99}:${PGID:-100} /var/www/metadata/createdTags.json + chown www-data:www-data /var/www/metadata/createdTags.json chmod 664 /var/www/metadata/createdTags.json -else - echo "ℹ️ createdTags.json already exists; preserving persistent data." fi -# Optionally, fix permissions for the rest of /var/www -echo "🔑 Fixing permissions for /var/www..." -find /var/www -type f -exec chmod 664 {} \; -find /var/www -type d -exec chmod 775 {} \; -chown -R ${PUID:-99}:${PGID:-100} /var/www - -echo "🔥 Final PHP configuration (99-custom.ini):" -cat /etc/php/8.3/apache2/conf.d/99-custom.ini - -echo "🔥 Final Apache configuration (limit_request_body.conf):" -cat /etc/apache2/conf-enabled/limit_request_body.conf - echo "🔥 Starting Apache..." -exec apachectl -D FOREGROUND +exec apachectl -D FOREGROUND \ No newline at end of file