diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fa89f53 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +# ===== Stage 1: Build the Angular app ===== +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files for caching +COPY package*.json ./ +RUN npm ci + +# Copy source code +COPY . . + +# Build for production +RUN npm run build -- --configuration production + +# ===== Stage 2: Serve static files with Nginx (app service) ===== +FROM nginx:alpine + +# Remove default Nginx files +RUN rm -rf /usr/share/nginx/html/* + +# Copy built Angular app +COPY --from=builder /app/dist/niayesh-hospital /usr/share/nginx/html + +# Copy app-specific Nginx config for SPA routing +COPY nginx_app.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a5cfde4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,45 @@ +services: + app: + image: niayesh-hospital:latest + container_name: hospital-app + restart: unless-stopped + expose: + - "80" + healthcheck: + test: ["CMD", "wget", "--spider", "http://localhost:80"] + interval: 30s + timeout: 10s + retries: 3 + logging: + driver: json-file + options: + max-size: 10m + nginx: + image: jonasal/nginx-certbot:latest + container_name: hospital-nginx + restart: unless-stopped + ports: + - 4200:80 + # Optional: Add for HTTPS - "4201:443" (or standard 443 if you change ports) + environment: + - CERTBOT_EMAIL=test@test.com + - ENVSUBST_TEMPLATE_SUFFIX=.tmpl + - CERTBOT_DISABLED=true # Set to false to enable auto-SSL (requires domain pointing to port 80) + volumes: + - ./nginx_user_conf.d:/etc/nginx/user_conf.d:ro + - letsencrypt:/etc/letsencrypt + # Adjust these cert paths to your server's actual location + - /home/devroot/HIS/certs/fullchain.pem:/etc/nginx/ssl/origin_cert.pem:ro + - /home/devroot/HIS/certs/prvkey.pem:/etc/nginx/ssl/origin_key.key:ro + depends_on: + app: + condition: service_healthy + logging: + driver: json-file + options: + max-size: 10m +networks: + default: + driver: bridge +volumes: + letsencrypt: \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..42520a3 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,23 @@ +server { + listen 80; + server_name localhost; + + root /usr/share/nginx/html; + index index.html; + + # This line is CRUCIAL for Angular routing + location / { + try_files $uri $uri/ /index.html; + } + + # Optional: aggressive caching for static assets + location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Security headers (optional but recommended) + add_header X-Content-Type-Options nosniff; + add_header X-Frame-Options DENY; + add_header X-XSS-Protection "1; mode=block"; +} \ No newline at end of file diff --git a/nginx_app.conf b/nginx_app.conf new file mode 100644 index 0000000..59dacdc --- /dev/null +++ b/nginx_app.conf @@ -0,0 +1,20 @@ +server { + listen 80; + server_name localhost; + + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot) { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + add_header X-Content-Type-Options nosniff; + add_header X-Frame-Options DENY; + add_header X-XSS-Protection "1; mode=block"; +} \ No newline at end of file diff --git a/nginx_user_conf.d/hospital.conf b/nginx_user_conf.d/hospital.conf new file mode 100644 index 0000000..e712afd --- /dev/null +++ b/nginx_user_conf.d/hospital.conf @@ -0,0 +1,12 @@ +server { + listen 80; + server_name hospital.networkwizard.xyz; + + location / { + proxy_pass http://hospital-app:80; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} \ No newline at end of file