-
-
Notifications
You must be signed in to change notification settings - Fork 229
Expand file tree
/
Copy pathDockerfile
More file actions
154 lines (117 loc) · 5.46 KB
/
Copy pathDockerfile
File metadata and controls
154 lines (117 loc) · 5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# Stage 1: Build the React frontend
FROM node:22-alpine AS console-frontend-builder
# Set working directory for the frontend
WORKDIR /build/console
# Copy frontend package files
COPY console/package*.json ./
# Install dependencies with retry settings for network resilience
RUN npm config set fetch-retries 5 && \
npm config set fetch-retry-mintimeout 20000 && \
npm config set fetch-retry-maxtimeout 120000 && \
npm ci
# Copy frontend source code
COPY console/ ./
# Build frontend in production mode
RUN npm run build
# Stage 2: Build the notification center frontend
FROM node:22-alpine AS notification-center-builder
# Set working directory for the notification center
WORKDIR /build/notification_center
# Copy notification center package files
COPY notification_center/package*.json ./
# Install dependencies with retry settings for network resilience
RUN npm config set fetch-retries 5 && \
npm config set fetch-retry-mintimeout 20000 && \
npm config set fetch-retry-maxtimeout 120000 && \
npm ci
# Copy notification center source code
COPY notification_center/ ./
# Build notification center in production mode
RUN npm run build
# Stage 2b: Build the web analytics browser SDK (embedded into the Go binary)
FROM node:22-alpine AS web-analytics-sdk-builder
WORKDIR /build/web_analytics_sdk
COPY web_analytics_sdk/package*.json ./
RUN npm config set fetch-retries 5 && \
npm config set fetch-retry-mintimeout 20000 && \
npm config set fetch-retry-maxtimeout 120000 && \
npm ci
COPY web_analytics_sdk/ ./
# The SDK version is read from the Go config at build time (single source of
# truth for the release), so that file must be present in this stage too.
COPY config/config.go /build/config/config.go
RUN npm run build
# Stage 3: Build the Go binary (pure Go, no CGO needed)
FROM golang:1.25-alpine AS backend-builder
# Set working directory
WORKDIR /build
# Install build dependencies
RUN apk add --no-cache git
# Copy go.mod and go.sum files
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy the source code
COPY cmd/ cmd/
COPY config/ config/
COPY internal/ internal/
COPY pkg/ pkg/
# Build the application with CGO disabled (pure Go)
ENV CGO_ENABLED=0
ENV GOOS=linux
RUN go build -ldflags="-s -w" -o /tmp/server ./cmd/api
# Stage 4: Create the runtime container (Alpine for smaller image)
FROM alpine:3.24
# Labels belong on the image that ships, not on a builder stage: a registry scanner reads
# the final manifest. BUSL-1.1 is the SPDX identifier for the Licensed Work; the AGPL half
# travels as its own file below, because /licenses is the directory a scanner opens.
LABEL org.opencontainers.image.title="Notifuse" \
org.opencontainers.image.source="https://github.com/Notifuse/notifuse" \
org.opencontainers.image.licenses="BUSL-1.1"
# Add necessary runtime packages.
#
# The upgrade is not decoration. The published alpine tag is rebuilt on its own schedule
# and routinely trails its own repository by a patch or two, so a registry scanner reads
# CVEs off the base image that the branch has already fixed and blocks the pull over a
# package the mirror would hand us patched. Upgrading first pins the image to the branch's
# current security level at build time rather than to whenever the tag was last rebuilt.
RUN apk upgrade --no-cache && \
apk add --no-cache \
ca-certificates \
tzdata \
postgresql-client
# Create application directory structure
WORKDIR /app
RUN mkdir -p /app/console/dist /app/notification_center/dist /app/web_analytics_sdk/dist /app/data /app/geoip
# Copy the binary from the builder stage
# The licence texts, in the directory a registry scanner opens. Both are needed: the image
# carries BSL bytes and AGPL bytes, and shipping only one of them misdescribes what is inside.
COPY LICENSE /licenses/LICENSE
COPY web_analytics_sdk/LICENSE /licenses/web_analytics_sdk-LICENSE
COPY --from=backend-builder /tmp/server /app/server
# Copy the built console files
COPY --from=console-frontend-builder /build/console/dist/ /app/console/dist/
# Copy the built notification center files
COPY --from=notification-center-builder /build/notification_center/dist/ /app/notification_center/dist/
# Ship the web analytics browser SDK as a static asset, not inside the binary.
# The bundle links ua-parser-js (AGPL-3.0-or-later), so embedding it would
# carry that code into the server binary itself; served from disk, the licence
# boundary stays at web_analytics_sdk/, which carries its own LICENSE and
# NOTICE. The server looks it up relative to its working directory (/app) and
# simply does not register /na.js if it is missing.
COPY --from=web-analytics-sdk-builder /build/web_analytics_sdk/dist/notifuse-analytics.min.js /app/web_analytics_sdk/dist/notifuse-analytics.min.js
COPY web_analytics_sdk/LICENSE /app/web_analytics_sdk/LICENSE
COPY web_analytics_sdk/NOTICE /app/web_analytics_sdk/NOTICE
# Ship the MaxMind GeoLite2 City database so web analytics resolves locations
# with no configuration. NOT under /app/data: compose bind-mounts the host's
# ./data over that directory, which would hide anything the image put there.
# A fresher database dropped in the mounted ./data takes precedence (see
# geoip.DefaultPaths), as does GEOIP_DB_PATH, neither needing a rebuild.
# This product includes GeoLite2 data created by MaxMind, available from
# https://www.maxmind.com.
COPY data/GeoLite2-City.mmdb /app/geoip/GeoLite2-City.mmdb
# Expose the application ports
EXPOSE 8080
EXPOSE 587
# Run the application
CMD ["/app/server"]