Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
189 lines (169 loc) · 6.68 KB
/
Copy pathDockerfile
File metadata and controls
189 lines (169 loc) · 6.68 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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# ============================================
# TeamPass Docker Image
# ============================================
# The PHP dependencies are not installed here: the repository ships them in app/vendor/
# with the production autoloader already generated, and the file integrity check compares
# them with app/files_reference.txt. Running `composer install` in the image regenerated
# Composer's own files (a random APCu prefix in autoload_real.php, the builder's
# InstalledVersions.php, a lock-derived autoloader suffix), which every container then
# reported as modified.
FROM php:8.3-fpm-alpine3.24
# Metadata labels
LABEL maintainer="TeamPass <nils@teampass.net>" \
org.opencontainers.image.title="TeamPass" \
org.opencontainers.image.description="Collaborative Passwords Manager" \
org.opencontainers.image.url="https://teampass.net" \
org.opencontainers.image.source="https://github.com/nilsteampassnet/TeamPass" \
org.opencontainers.image.documentation="https://documentation.teampass.net" \
org.opencontainers.image.licenses="GPL-3.0" \
org.opencontainers.image.vendor="TeamPass"
# Build arguments
# The CI workflow overrides this with the value it reads from app/config/include.php,
# so every published image reports the version it actually contains (a branch build
# used to be labelled "master"). The default only serves local builds, so it must stay
# equal to TP_VERSION.TP_VERSION_MINOR; the release procedure bumps it in the same
# commit as the version constants.
ARG TEAMPASS_VERSION=3.2.2.8
ENV TEAMPASS_VERSION=${TEAMPASS_VERSION}
# Apply the Alpine security updates published since the base image was built.
#
# openssl and curl are not installed below - they come with php:8.3-fpm-alpine3.24 - so
# nothing here ever refreshed them, and the image shipped whatever the base image froze.
# That is what accumulated as Trivy alerts (libcrypto3/libssl3/openssl and curl/libcurl),
# all of them fixed upstream in the very branch the image already tracks.
#
# The trade-off is deliberate: the build stops being byte-reproducible across time, in
# exchange for never publishing an image with known-vulnerable OS packages. Pinning the
# fixed versions instead would keep reproducibility but has to be edited at every CVE.
#
# Placed AFTER the version ARG on purpose: that argument changes at every release, so this
# layer is invalidated with it and a release build always resolves fresh packages.
RUN apk upgrade --no-cache
# Install system dependencies and PHP extensions
RUN apk add --no-cache \
# System packages
nginx \
supervisor \
busybox-suid \
netcat-openbsd \
# Libraries for PHP extensions
gnu-libiconv \
libldap \
gmp \
icu-libs \
libzip \
freetype \
libjpeg-turbo \
libpng \
libxml2 \
oniguruma \
&& apk add --no-cache --virtual .build-deps \
# Build dependencies
$PHPIZE_DEPS \
openldap-dev \
gmp-dev \
icu-dev \
libzip-dev \
freetype-dev \
libjpeg-turbo-dev \
libpng-dev \
libxml2-dev \
oniguruma-dev \
# Configure and install PHP extensions
&& docker-php-ext-configure gd \
--with-freetype \
--with-jpeg \
&& docker-php-ext-configure ldap \
&& docker-php-ext-install -j$(nproc) \
mysqli \
pdo_mysql \
bcmath \
ldap \
gmp \
gd \
zip \
intl \
opcache \
mbstring \
xml \
# Cleanup build dependencies
&& apk del .build-deps \
&& rm -rf /var/cache/apk/* /tmp/* /var/tmp/*
# No LD_PRELOAD of preloadable_libiconv.so on purpose: Alpine has not shipped that
# file for several releases. The gnu-libiconv package only provides the gnu-iconv
# binary, and gnu-libiconv-libs provides libiconv.so.2, which exports the prefixed
# symbols (libiconv_open, …) and therefore cannot shadow musl's iconv. Setting the
# classic workaround would only make every process log an ld.so error. PHP uses
# musl's iconv.
# Copy PHP configuration
COPY docker/php/php.ini /usr/local/etc/php/conf.d/teampass.ini
# Copy Nginx configuration
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY docker/nginx/teampass.conf /etc/nginx/http.d/default.conf
# Copy Supervisor configuration
COPY docker/supervisor/supervisord.conf /etc/supervisor/supervisord.conf
# Create application directory
WORKDIR /var/www/html
# Copy application files
COPY --chown=nginx:nginx . .
# A build context taken from a development clone may also hold Composer's development
# packages, which are never tracked. Remove them with the bundled offline cleanup (the same
# logic as install/upgrade); on a clean checkout there is nothing to remove.
RUN php app/scripts/cleanup_dev_dependencies.php
# Create required directories with proper permissions
RUN mkdir -p \
storage/sk \
storage/files \
storage/upload \
storage/config \
storage/backups \
secrets \
app/includes/libraries/csrfp/log \
/var/lib/nginx/tmp \
/var/log/supervisor \
/run/nginx \
&& chown -R nginx:nginx \
storage \
storage/sk \
storage/files \
storage/upload \
storage/config \
storage/backups \
secrets \
app/includes/libraries/csrfp/log \
/var/lib/nginx \
/var/log \
/run/nginx \
&& chmod 700 storage/sk secrets \
&& chmod 750 storage storage/files storage/upload storage/config storage/backups app/includes/libraries/csrfp/log
# Remove unnecessary files for production
RUN rm -rf \
.git \
.github \
tests \
.gitignore \
.dockerignore \
.scrutinizer.yml \
.codacy.yml \
.eslintrc \
teampass-docker-start.sh \
Dockerfile
# Setup cron for TeamPass scheduler
RUN echo "* * * * * php /var/www/html/app/sources/scheduler.php > /dev/null 2>&1" > /var/spool/cron/crontabs/nginx \
&& chmod 600 /var/spool/cron/crontabs/nginx
# Copy and set entrypoint script
COPY docker/docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
# Health check
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost/health || exit 1
# Expose HTTP port
EXPOSE 80
# Define volumes for persistent data.
# storage/config holds the install state (settings.php, csrfp.config.php) and
# secrets holds the Defuse master key: both must persist across container
# recreation, otherwise TeamPass would try to reinstall itself (issue #5236).
VOLUME ["/var/www/html/storage/sk", "/var/www/html/storage/files", "/var/www/html/storage/upload", "/var/www/html/storage/config", "/var/www/html/secrets"]
# Set entrypoint and default command
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]