feat: Consolidate client and server into a single Docker image and update Docker Compose configuration.
This commit is contained in:
37
Dockerfile
Normal file
37
Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Build stage - build client assets
|
||||||
|
FROM node:20-alpine AS client-builder
|
||||||
|
|
||||||
|
WORKDIR /app/client
|
||||||
|
COPY client/package.json client/package-lock.json* ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY client/ ./
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production stage - run server with built client
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy server package files and install dependencies
|
||||||
|
COPY package.json package-lock.json* ./
|
||||||
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
|
# Copy server source
|
||||||
|
COPY server ./server
|
||||||
|
|
||||||
|
# Copy built client assets
|
||||||
|
COPY --from=client-builder /app/client/dist ./client/dist
|
||||||
|
|
||||||
|
# Create data directory for SQLite
|
||||||
|
RUN mkdir -p /app/data
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=3000
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node", "server/index.js"]
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
services:
|
services:
|
||||||
server:
|
app:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: server/Dockerfile
|
dockerfile: Dockerfile
|
||||||
expose:
|
expose:
|
||||||
- "3000"
|
- "3000"
|
||||||
volumes:
|
volumes:
|
||||||
@@ -10,6 +10,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- PORT=3000
|
- PORT=3000
|
||||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-123456}
|
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-123456}
|
||||||
|
- NODE_ENV=production
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
|
||||||
@@ -18,23 +19,5 @@ services:
|
|||||||
retries: 3
|
retries: 3
|
||||||
start_period: 10s
|
start_period: 10s
|
||||||
|
|
||||||
client:
|
|
||||||
build:
|
|
||||||
context: ./client
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
# No ports binding - Coolify's reverse proxy handles external traffic
|
|
||||||
expose:
|
|
||||||
- "80"
|
|
||||||
depends_on:
|
|
||||||
server:
|
|
||||||
condition: service_healthy
|
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 3s
|
|
||||||
retries: 3
|
|
||||||
start_period: 5s
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
eventy_data:
|
eventy_data:
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ initDb();
|
|||||||
app.use('/api', routes);
|
app.use('/api', routes);
|
||||||
|
|
||||||
// Serve static files from the React app build directory
|
// Serve static files from the React app build directory
|
||||||
app.use(express.static(path.join(__dirname, '../client/dist')));
|
// In Docker container, this is at /app/client/dist
|
||||||
|
const staticPath = process.env.NODE_ENV === 'production'
|
||||||
|
? path.join(__dirname, '../client/dist')
|
||||||
|
: path.join(__dirname, '../client/dist');
|
||||||
|
app.use(express.static(staticPath));
|
||||||
|
|
||||||
// Handle social previews for shared event links
|
// Handle social previews for shared event links
|
||||||
app.get('/event/:id', (req, res) => {
|
app.get('/event/:id', (req, res) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user