From 922e42548f79faa4c54a3c054e1f2bac615f5aab Mon Sep 17 00:00:00 2001 From: Lalit Sudhir Date: Thu, 23 Oct 2025 19:42:34 -0700 Subject: [PATCH] migrate to nginx-unprivileged for enhanced security --- Dockerfile | 24 ++++++++------------ README.md | 20 +++++++---------- SECURITY.md | 50 ++++++++++++++++++++---------------------- docker-compose.dev.yml | 6 ++--- docker-compose.yml | 2 +- nginx.conf | 4 ++-- 6 files changed, 46 insertions(+), 60 deletions(-) diff --git a/Dockerfile b/Dockerfile index 84d70a0..63d3742 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,24 +15,18 @@ ENV SIMPLE_MODE=$SIMPLE_MODE RUN npm run build -- --mode production # Production stage -FROM nginx:alpine - -ARG APP_USER_ID=1001 -ARG APP_GROUP_ID=1001 - -RUN addgroup -g $APP_GROUP_ID bentopdf && \ - adduser -u $APP_USER_ID -G bentopdf -D -s /bin/sh bentopdf +FROM nginxinc/nginx-unprivileged:1.29-alpine +# Copy files as root first, then change ownership COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/nginx.conf -RUN mkdir -p /var/cache/nginx /var/log/nginx /var/run/nginx && \ - chown -R bentopdf:bentopdf /usr/share/nginx/html /var/cache/nginx /var/log/nginx /var/run/nginx +# Change ownership while still root, then switch to nginx user +USER root +RUN mkdir -p /etc/nginx/tmp && \ + chown -R nginx:nginx /usr/share/nginx/html /etc/nginx/tmp +USER nginx -RUN sed -i 's/user nginx;/user bentopdf;/' /etc/nginx/nginx.conf +EXPOSE 8080 -EXPOSE 80 - -USER bentopdf - -CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file +CMD ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md index bec307c..f9f7599 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ You can run BentoPDF locally for development or personal use. You can run BentoPDF directly from Docker Hub without cloning the repository: ```bash -docker run -p 3000:80 bentopdf/bentopdf:latest +docker run -p 3000:8080 bentopdf/bentopdf:latest ``` Open your browser at: http://localhost:3000 @@ -124,7 +124,7 @@ services: image: bentopdf/bentopdf:latest container_name: bentopdf ports: - - '3000:80' + - '3000:8080' restart: unless-stopped ``` @@ -151,21 +151,17 @@ For more details, see [SIMPLE_MODE.md](SIMPLE_MODE.md). ### 🔒 Security Features -BentoPDF runs as a non-root user for enhanced security: +BentoPDF runs as a non-root user using nginx-unprivileged for enhanced security: -- **Non-Root Execution**: Container runs with minimal privileges -- **Configurable UID/GID**: Customize user/group IDs for your environment +- **Non-Root Execution**: Container runs with minimal privileges using nginx-unprivileged +- **Port 8080**: Uses high port number to avoid requiring root privileges - **Security Best Practices**: Follows Principle of Least Privilege -#### Custom User Configuration +#### Basic Usage ```bash -docker build \ - --build-arg APP_USER_ID=2000 \ - --build-arg APP_GROUP_ID=2000 \ - -t bentopdf . - -docker run -p 8080:80 bentopdf +docker build -t bentopdf . +docker run -p 8080:8080 bentopdf ``` For detailed security configuration, see [SECURITY.md](SECURITY.md). diff --git a/SECURITY.md b/SECURITY.md index c067111..c3510fd 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Non-Root User Support -BentoPDF now supports running as a non-root user for enhanced security. This follows the Principle of Least Privilege and is essential for production environments. +BentoPDF now uses nginx-unprivileged for enhanced security. This follows the Principle of Least Privilege and is essential for production environments. ### Security Benefits @@ -13,22 +13,19 @@ BentoPDF now supports running as a non-root user for enhanced security. This fol ### Usage -#### Default Configuration (UID/GID 1001) +#### Default Configuration (nginx-unprivileged) ```bash docker build -t bentopdf . -docker run -p 8080:80 bentopdf +docker run -p 8080:8080 bentopdf ``` -#### Custom UID/GID +#### Simple Mode ```bash -# Build with custom user/group IDs -docker build \ - --build-arg APP_USER_ID=2000 \ - --build-arg APP_GROUP_ID=2000 \ - -t bentopdf . +# Build with simple mode enabled +docker build --build-arg SIMPLE_MODE=true -t bentopdf-simple . # Run the container -docker run -p 8080:80 bentopdf +docker run -p 8080:8080 bentopdf-simple ``` #### Kubernetes Example @@ -48,7 +45,7 @@ spec: - name: bentopdf image: bentopdf:latest ports: - - containerPort: 80 + - containerPort: 8080 ``` #### Docker Compose Example @@ -60,10 +57,9 @@ services: context: . dockerfile: Dockerfile args: - APP_USER_ID: 2000 - APP_GROUP_ID: 2000 + SIMPLE_MODE: false ports: - - "8080:80" + - "8080:8080" security_opt: - no-new-privileges:true ``` @@ -75,18 +71,18 @@ To verify the container is running as non-root: ```bash # Check the user inside the container docker exec whoami -# Should output: bentopdf +# Should output: nginx # Check the user ID docker exec id -# Should show UID/GID matching your configuration +# Should show UID/GID for nginx user (typically 101) ``` ### Security Best Practices -1. **Use specific UID/GID**: Don't use 0 (root) or common system UIDs -2. **Regular Updates**: Keep the base image updated -3. **Minimal Permissions**: Only grant necessary file permissions +1. **Use nginx-unprivileged**: Built-in non-root user with minimal privileges +2. **Regular Updates**: Keep the base image updated (currently using 1.29-alpine) +3. **Port 8080**: Use high port numbers to avoid requiring root privileges 4. **Security Scanning**: Regularly scan images for vulnerabilities 5. **Network Policies**: Implement network segmentation @@ -94,15 +90,17 @@ docker exec id If you encounter permission issues: -1. **Check file ownership**: Ensure all application files are owned by the bentopdf user -2. **Verify UID/GID**: Make sure the configured IDs don't conflict with host system -3. **Directory permissions**: Ensure nginx can write to log and cache directories +1. **Check file ownership**: Ensure all application files are owned by the nginx user +2. **Verify PID directory**: Ensure `/etc/nginx/tmp/` directory exists and is writable +3. **Port binding**: Ensure port 8080 is available and not blocked by firewall ### Migration from Root If migrating from a root-based setup: -1. Update your Dockerfile to use the new non-root configuration -2. Rebuild your images with the new security settings -3. Update your deployment configurations (Kubernetes, Docker Compose, etc.) -4. Test thoroughly in a staging environment +1. Update your Dockerfile to use nginx-unprivileged base image +2. Change port mappings from 80 to 8080 in all configurations +3. Update nginx.conf to use `/etc/nginx/tmp/nginx.pid` for PID file +4. Rebuild your images with the new security settings +5. Update your deployment configurations (Kubernetes, Docker Compose, etc.) +6. Test thoroughly in a staging environment diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 600eaa7..f630066 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -4,10 +4,8 @@ services: context: . dockerfile: Dockerfile args: - APP_USER_ID: 1001 // default value is 1001 can be customized to any other value - APP_GROUP_ID: 1001 // default value is 1001 can be customized to any other value - SIMPLE_MODE: false // false for default mode, true for simple mode + SIMPLE_MODE: true # false for default mode, true for simple mode container_name: bentopdf ports: - - '3000:80' + - '3000:8080' restart: unless-stopped diff --git a/docker-compose.yml b/docker-compose.yml index 29f39a7..a95e106 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,4 +6,4 @@ services: container_name: bentopdf restart: unless-stopped ports: - - '3000:80' + - '3000:8080' diff --git a/nginx.conf b/nginx.conf index 27d2496..a34d06a 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,4 +1,4 @@ -pid /var/run/nginx/nginx.pid; +pid /etc/nginx/tmp/nginx.pid; events { worker_connections 1024; @@ -17,7 +17,7 @@ http { gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json; server { - listen 80; + listen 8080; server_name localhost; root /usr/share/nginx/html; index index.html;