diff --git a/Dockerfile b/Dockerfile index 4c04b31..98e07a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,10 +31,11 @@ COPY data-api.js /usr/share/nginx/api/ COPY backup-s3.js /usr/share/nginx/api/ COPY auth-middleware.js /usr/share/nginx/api/ COPY login.html /usr/share/nginx/api/ -COPY inject-password-hash.js /usr/share/nginx/api/ +COPY generate-htpasswd.js /usr/share/nginx/api/ # Copy a custom Nginx configuration that includes the data API proxy COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY nginx-auth.conf /etc/nginx/auth.conf # Copy supervisor configuration COPY supervisord.conf /etc/supervisord.conf diff --git a/generate-htpasswd.js b/generate-htpasswd.js new file mode 100644 index 0000000..2081f01 --- /dev/null +++ b/generate-htpasswd.js @@ -0,0 +1,33 @@ +/** + * Generate .htpasswd file for Nginx basic authentication + * + * This script creates a .htpasswd file from the bcrypt hash provided in the + * PASSWORD_HASH environment variable. + */ + +const fs = require('fs'); +const path = require('path'); + +// Default username +const USERNAME = 'user'; + +// Get password hash from environment variable +const passwordHash = process.env.PASSWORD_HASH || '$2a$10$EgxHKjDDFcZKtQY9hl/N4.QvEQHCXVnQXw9dzFYlUDVKOcLMGp9eq'; + +// Format for .htpasswd: username:$2y$...hash... +// Note: Nginx requires $2y$ format instead of bcrypt's $2a$ format +const htpasswdContent = `${USERNAME}:${passwordHash.replace('$2a$', '$2y$')}`; + +// Path to the .htpasswd file +const htpasswdPath = '/etc/nginx/.htpasswd'; + +// Write the .htpasswd file +try { + fs.writeFileSync(htpasswdPath, htpasswdContent); + console.log(`Generated .htpasswd file at ${htpasswdPath}`); +} catch (error) { + console.error(`Error generating .htpasswd file: ${error.message}`); + process.exit(1); +} + +console.log('Basic authentication setup complete'); diff --git a/generate-password.js b/generate-password.js new file mode 100644 index 0000000..eb4ce5c --- /dev/null +++ b/generate-password.js @@ -0,0 +1,42 @@ +/** + * Password Hash Generator for Weight Tracker + * + * This script generates a bcrypt hash for a given password that can be used + * with the Weight Tracker application's authentication system. + * + * Usage: + * node generate-password.js + */ + +const bcrypt = require('bcryptjs'); + +// Get password from command line arguments +const password = process.argv[2]; + +if (!password) { + console.error('Error: Password is required'); + console.log('Usage: node generate-password.js '); + process.exit(1); +} + +// Generate salt and hash +const saltRounds = 10; +bcrypt.genSalt(saltRounds, (err, salt) => { + if (err) { + console.error('Error generating salt:', err); + process.exit(1); + } + + bcrypt.hash(password, salt, (err, hash) => { + if (err) { + console.error('Error generating hash:', err); + process.exit(1); + } + + console.log('\nPassword Hash for Nginx Basic Authentication:'); + console.log(hash); + console.log('\nUse this hash in your PASSWORD_HASH environment variable in Coolify.'); + console.log('Example:'); + console.log(`PASSWORD_HASH=${hash}`); + }); +}); diff --git a/nginx-auth.conf b/nginx-auth.conf new file mode 100644 index 0000000..8b210d5 --- /dev/null +++ b/nginx-auth.conf @@ -0,0 +1,13 @@ +# Authentication configuration for Nginx +# This file will be included in the main Nginx configuration + +# Define the authentication realm +auth_basic "Weight Tracker"; + +# Path to the .htpasswd file containing user credentials +auth_basic_user_file /etc/nginx/.htpasswd; + +# CORS headers +add_header 'Access-Control-Allow-Origin' '*' always; +add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; +add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always; diff --git a/nginx.conf b/nginx.conf index f904a72..3649b1b 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,29 +1,19 @@ server { listen 80; - server_name _; - root /usr/share/nginx/html; - index index.html; - - # Enable compression + server_name localhost; + + # Enable gzip compression gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; - # Authentication check - redirect to login if not authenticated - location = / { - # First try to use the API to check authentication - auth_request /auth/check; + # Protect all routes with basic authentication + location / { + # Include authentication configuration + include /etc/nginx/auth.conf; - # If auth passes, serve the main page + # Serve static files try_files $uri $uri/ /index.html; - # CORS headers - add_header 'Access-Control-Allow-Origin' '*' always; - add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; - add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always; - - # Error indicates not authenticated, redirect to login - error_page 401 = @error401; - # Handle preflight requests if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; @@ -35,21 +25,6 @@ server { return 204; } } - - # Serve static files directly - location / { - try_files $uri $uri/ /index.html; - - # CORS headers - add_header 'Access-Control-Allow-Origin' '*' always; - add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; - add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always; - } - - # Handle 401 unauthorized by redirecting to login - location @error401 { - return 302 /login; - } # Proxy requests to the data API location /data/ { diff --git a/supervisord.conf b/supervisord.conf index b4ec1a8..77ea2b3 100644 --- a/supervisord.conf +++ b/supervisord.conf @@ -5,8 +5,8 @@ logfile=/dev/stdout logfile_maxbytes=0 pidfile=/var/run/supervisord.pid -[program:inject-password-hash] -command=node /usr/share/nginx/api/inject-password-hash.js +[program:generate-htpasswd] +command=node /usr/share/nginx/api/generate-htpasswd.js directory=/usr/share/nginx/api environment=PASSWORD_HASH="%(ENV_PASSWORD_HASH)s" autostart=true