Skip to content

Commit 8cf59b6

Browse files
committed
docs: added documentation for production usage with Portainer
1 parent 8074b29 commit 8cf59b6

File tree

12 files changed

+1639
-56
lines changed

12 files changed

+1639
-56
lines changed

docker-compose.prod.yml

Lines changed: 397 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,397 @@
1+
# Production Docker Compose for phpMyFAQ
2+
# For use with Portainer or production deployments
3+
#
4+
# IMPORTANT: Before deploying:
5+
# 1. Copy .env.example to .env and configure all variables
6+
# 2. Choose your database service (mariadb OR postgres)
7+
# 3. Choose your web server (apache OR nginx+php-fpm OR frankenphp)
8+
# 4. Configure SSL certificates
9+
# 5. Review and adjust resource limits based on your needs
10+
#
11+
# Deploy with: docker-compose -f docker-compose.prod.yml up -d
12+
13+
version: '3.8'
14+
15+
services:
16+
# ========================================
17+
# Database Services (Choose ONE)
18+
# ========================================
19+
20+
mariadb:
21+
image: mariadb:11.6
22+
container_name: phpmyfaq-mariadb
23+
restart: unless-stopped
24+
environment:
25+
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
26+
- MYSQL_DATABASE=${MYSQL_DATABASE:-phpmyfaq}
27+
- MYSQL_USER=${MYSQL_USER:-phpmyfaq}
28+
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
29+
- MYSQL_ROOT_HOST=172.%.%.%
30+
volumes:
31+
- mariadb_data:/var/lib/mysql
32+
networks:
33+
- phpmyfaq-network
34+
healthcheck:
35+
test: ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized']
36+
interval: 30s
37+
timeout: 10s
38+
retries: 5
39+
start_period: 30s
40+
deploy:
41+
resources:
42+
limits:
43+
cpus: '2'
44+
memory: 2G
45+
reservations:
46+
cpus: '0.5'
47+
memory: 512M
48+
# Security: Don't expose database port to host in production
49+
# ports:
50+
# - '3306:3306'
51+
52+
postgres:
53+
image: postgres:17-alpine
54+
container_name: phpmyfaq-postgres
55+
restart: unless-stopped
56+
environment:
57+
- POSTGRES_DB=${POSTGRES_DB:-phpmyfaq}
58+
- POSTGRES_USER=${POSTGRES_USER:-phpmyfaq}
59+
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
60+
- POSTGRES_INITDB_ARGS=--encoding=UTF8 --lc-collate=C --lc-ctype=C
61+
volumes:
62+
- postgres_data:/var/lib/postgresql/data
63+
networks:
64+
- phpmyfaq-network
65+
healthcheck:
66+
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-phpmyfaq}']
67+
interval: 30s
68+
timeout: 10s
69+
retries: 5
70+
start_period: 30s
71+
deploy:
72+
resources:
73+
limits:
74+
cpus: '2'
75+
memory: 2G
76+
reservations:
77+
cpus: '0.5'
78+
memory: 512M
79+
# Security: Don't expose database port to host in production
80+
# ports:
81+
# - '5432:5432'
82+
83+
# ========================================
84+
# Web Server Services (Choose ONE)
85+
# ========================================
86+
87+
# Option 1: Apache with mod_php
88+
apache:
89+
image: phpmyfaq/phpmyfaq:${PMF_VERSION:-latest}
90+
container_name: phpmyfaq-apache
91+
restart: unless-stopped
92+
environment:
93+
# Database Configuration
94+
- PMF_DB_HOST=${PMF_DB_HOST:-mariadb}
95+
- PMF_DB_NAME=${PMF_DB_NAME:-phpmyfaq}
96+
- PMF_DB_USER=${PMF_DB_USER:-phpmyfaq}
97+
- PMF_DB_PASS=${PMF_DB_PASS}
98+
- PMF_DB_TYPE=${PMF_DB_TYPE:-mysqli}
99+
100+
# phpMyFAQ Configuration
101+
- PMF_TIMEZONE=${PMF_TIMEZONE:-UTC}
102+
- PMF_ENABLE_UPLOADS=${PMF_ENABLE_UPLOADS:-On}
103+
- PMF_DISABLE_HTACCESS=${PMF_DISABLE_HTACCESS:-}
104+
- PMF_MEMORY_LIMIT=${PMF_MEMORY_LIMIT:-512M}
105+
106+
# PHP Production Settings
107+
- PHP_LOG_ERRORS=On
108+
- PHP_ERROR_REPORTING=E_ALL & ~E_DEPRECATED & ~E_STRICT
109+
- PHP_DISPLAY_ERRORS=Off
110+
- PHP_DISPLAY_STARTUP_ERRORS=Off
111+
112+
# Search Engine Configuration (Optional)
113+
- ELASTICSEARCH_BASE_URI=${ELASTICSEARCH_BASE_URI:-}
114+
- OPENSEARCH_BASE_URI=${OPENSEARCH_BASE_URI:-}
115+
- SEARCH_WAIT_TIMEOUT=${SEARCH_WAIT_TIMEOUT:-30}
116+
volumes:
117+
# Data persistence
118+
- phpmyfaq_data:/var/www/html/data
119+
- phpmyfaq_images:/var/www/html/images
120+
- phpmyfaq_attachments:/var/www/html/attachments
121+
122+
# Configuration (optional - for persistent config)
123+
- phpmyfaq_config:/var/www/html/content/core/config
124+
125+
# Custom SSL certificates (if needed)
126+
# - ./ssl/cert.pem:/etc/ssl/certs/phpmyfaq.pem:ro
127+
# - ./ssl/cert-key.pem:/etc/ssl/private/phpmyfaq-key.pem:ro
128+
ports:
129+
- '${PMF_HTTP_PORT:-80}:80'
130+
- '${PMF_HTTPS_PORT:-443}:443'
131+
networks:
132+
- phpmyfaq-network
133+
depends_on:
134+
mariadb:
135+
condition: service_healthy
136+
# postgres:
137+
# condition: service_healthy
138+
healthcheck:
139+
test: ['CMD', 'curl', '-f', 'http://localhost/api/health']
140+
interval: 30s
141+
timeout: 10s
142+
retries: 3
143+
start_period: 60s
144+
deploy:
145+
resources:
146+
limits:
147+
cpus: '2'
148+
memory: 2G
149+
reservations:
150+
cpus: '0.5'
151+
memory: 512M
152+
153+
# Option 2: Nginx + PHP-FPM (uncomment to use)
154+
# nginx:
155+
# image: nginx:alpine
156+
# container_name: phpmyfaq-nginx
157+
# restart: unless-stopped
158+
# volumes:
159+
# - phpmyfaq_data:/var/www/html
160+
# - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
161+
# - ./nginx/conf.d:/etc/nginx/conf.d:ro
162+
# - ./ssl/cert.pem:/etc/ssl/certs/phpmyfaq.pem:ro
163+
# - ./ssl/cert-key.pem:/etc/ssl/private/phpmyfaq-key.pem:ro
164+
# - nginx_logs:/var/log/nginx
165+
# ports:
166+
# - "${PMF_HTTP_PORT:-80}:80"
167+
# - "${PMF_HTTPS_PORT:-443}:443"
168+
# networks:
169+
# - phpmyfaq-network
170+
# depends_on:
171+
# - php-fpm
172+
# healthcheck:
173+
# test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"]
174+
# interval: 30s
175+
# timeout: 10s
176+
# retries: 3
177+
# deploy:
178+
# resources:
179+
# limits:
180+
# cpus: '1'
181+
# memory: 512M
182+
#
183+
# php-fpm:
184+
# image: phpmyfaq/phpmyfaq:${PMF_VERSION:-latest}-fpm
185+
# container_name: phpmyfaq-php-fpm
186+
# restart: unless-stopped
187+
# environment:
188+
# # Same environment variables as Apache service
189+
# - PMF_DB_HOST=${PMF_DB_HOST:-mariadb}
190+
# - PMF_DB_NAME=${PMF_DB_NAME:-phpmyfaq}
191+
# - PMF_DB_USER=${PMF_DB_USER:-phpmyfaq}
192+
# - PMF_DB_PASS=${PMF_DB_PASS}
193+
# - PMF_DB_TYPE=${PMF_DB_TYPE:-mysqli}
194+
# - PMF_TIMEZONE=${PMF_TIMEZONE:-UTC}
195+
# - PMF_ENABLE_UPLOADS=${PMF_ENABLE_UPLOADS:-On}
196+
# - PMF_MEMORY_LIMIT=${PMF_MEMORY_LIMIT:-512M}
197+
# - PHP_LOG_ERRORS=On
198+
# - PHP_ERROR_REPORTING=E_ALL & ~E_DEPRECATED & ~E_STRICT
199+
# - PHP_DISPLAY_ERRORS=Off
200+
# volumes:
201+
# - phpmyfaq_data:/var/www/html
202+
# networks:
203+
# - phpmyfaq-network
204+
# depends_on:
205+
# mariadb:
206+
# condition: service_healthy
207+
# healthcheck:
208+
# test: ["CMD-SHELL", "php-fpm-healthcheck"]
209+
# interval: 30s
210+
# timeout: 10s
211+
# retries: 3
212+
# start_period: 60s
213+
# deploy:
214+
# resources:
215+
# limits:
216+
# cpus: '2'
217+
# memory: 2G
218+
# reservations:
219+
# cpus: '0.5'
220+
# memory: 512M
221+
222+
# Option 3: FrankenPHP (modern PHP server with HTTP/3 support)
223+
# frankenphp:
224+
# image: phpmyfaq/phpmyfaq:${PMF_VERSION:-latest}-frankenphp
225+
# container_name: phpmyfaq-frankenphp
226+
# restart: unless-stopped
227+
# environment:
228+
# # Same environment variables as Apache service
229+
# - PMF_DB_HOST=${PMF_DB_HOST:-mariadb}
230+
# - PMF_DB_NAME=${PMF_DB_NAME:-phpmyfaq}
231+
# - PMF_DB_USER=${PMF_DB_USER:-phpmyfaq}
232+
# - PMF_DB_PASS=${PMF_DB_PASS}
233+
# - PMF_DB_TYPE=${PMF_DB_TYPE:-mysqli}
234+
# - PMF_TIMEZONE=${PMF_TIMEZONE:-UTC}
235+
# - PMF_ENABLE_UPLOADS=${PMF_ENABLE_UPLOADS:-On}
236+
# - PMF_MEMORY_LIMIT=${PMF_MEMORY_LIMIT:-512M}
237+
# - PHP_LOG_ERRORS=On
238+
# - PHP_ERROR_REPORTING=E_ALL & ~E_DEPRECATED & ~E_STRICT
239+
# - PHP_DISPLAY_ERRORS=Off
240+
# - SERVER_NAME=${SERVER_NAME:-:80}
241+
# volumes:
242+
# - phpmyfaq_data:/var/www/html
243+
# - caddy_data:/data
244+
# - caddy_config:/config
245+
# # Custom SSL certificates (if needed)
246+
# # - ./ssl/cert.pem:/etc/ssl/certs/phpmyfaq.pem:ro
247+
# # - ./ssl/cert-key.pem:/etc/ssl/private/phpmyfaq-key.pem:ro
248+
# ports:
249+
# - "${PMF_HTTP_PORT:-80}:80"
250+
# - "${PMF_HTTPS_PORT:-443}:443"
251+
# - "${PMF_HTTP3_PORT:-443}:443/udp"
252+
# networks:
253+
# - phpmyfaq-network
254+
# depends_on:
255+
# mariadb:
256+
# condition: service_healthy
257+
# healthcheck:
258+
# test: ["CMD", "curl", "-f", "http://localhost/api/health"]
259+
# interval: 30s
260+
# timeout: 10s
261+
# retries: 3
262+
# start_period: 60s
263+
# deploy:
264+
# resources:
265+
# limits:
266+
# cpus: '2'
267+
# memory: 2G
268+
# reservations:
269+
# cpus: '0.5'
270+
# memory: 512M
271+
272+
# ========================================
273+
# Search Engine Services (Optional)
274+
# ========================================
275+
276+
elasticsearch:
277+
image: elasticsearch:8.16.5
278+
container_name: phpmyfaq-elasticsearch
279+
restart: unless-stopped
280+
environment:
281+
- cluster.name=phpmyfaq-cluster
282+
- node.name=phpmyfaq-node
283+
- discovery.type=single-node
284+
- bootstrap.memory_lock=true
285+
- xpack.security.enabled=${ES_SECURITY_ENABLED:-false}
286+
- 'ES_JAVA_OPTS=-Xms1g -Xmx1g'
287+
ulimits:
288+
memlock:
289+
soft: -1
290+
hard: -1
291+
nofile:
292+
soft: 65536
293+
hard: 65536
294+
volumes:
295+
- elasticsearch_data:/usr/share/elasticsearch/data
296+
networks:
297+
- phpmyfaq-network
298+
healthcheck:
299+
test: ['CMD-SHELL', 'curl -f http://localhost:9200/_cluster/health || exit 1']
300+
interval: 30s
301+
timeout: 10s
302+
retries: 5
303+
start_period: 60s
304+
deploy:
305+
resources:
306+
limits:
307+
cpus: '2'
308+
memory: 2G
309+
reservations:
310+
cpus: '1'
311+
memory: 1G
312+
# Security: Don't expose Elasticsearch port to host in production
313+
# ports:
314+
# - '9200:9200'
315+
316+
# Alternative: OpenSearch (uncomment to use instead of Elasticsearch)
317+
# opensearch:
318+
# image: opensearchproject/opensearch:2.19.2
319+
# container_name: phpmyfaq-opensearch
320+
# restart: unless-stopped
321+
# environment:
322+
# - cluster.name=phpmyfaq-cluster
323+
# - node.name=phpmyfaq-node
324+
# - discovery.type=single-node
325+
# - bootstrap.memory_lock=true
326+
# - DISABLE_INSTALL_DEMO_CONFIG=true
327+
# - DISABLE_SECURITY_PLUGIN=${OPENSEARCH_DISABLE_SECURITY:-true}
328+
# - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
329+
# ulimits:
330+
# memlock:
331+
# soft: -1
332+
# hard: -1
333+
# nofile:
334+
# soft: 65536
335+
# hard: 65536
336+
# volumes:
337+
# - opensearch_data:/usr/share/opensearch/data
338+
# networks:
339+
# - phpmyfaq-network
340+
# healthcheck:
341+
# test: ["CMD-SHELL", "curl -f http://localhost:9200/_cluster/health || exit 1"]
342+
# interval: 30s
343+
# timeout: 10s
344+
# retries: 5
345+
# start_period: 60s
346+
# deploy:
347+
# resources:
348+
# limits:
349+
# cpus: '2'
350+
# memory: 2G
351+
# reservations:
352+
# cpus: '1'
353+
# memory: 1G
354+
355+
# ========================================
356+
# Networks
357+
# ========================================
358+
networks:
359+
phpmyfaq-network:
360+
driver: bridge
361+
ipam:
362+
config:
363+
- subnet: 172.20.0.0/16
364+
365+
# ========================================
366+
# Volumes
367+
# ========================================
368+
volumes:
369+
# Database volumes
370+
mariadb_data:
371+
driver: local
372+
postgres_data:
373+
driver: local
374+
375+
# phpMyFAQ data volumes
376+
phpmyfaq_data:
377+
driver: local
378+
phpmyfaq_images:
379+
driver: local
380+
phpmyfaq_attachments:
381+
driver: local
382+
phpmyfaq_config:
383+
driver: local
384+
385+
# Search engine volumes
386+
elasticsearch_data:
387+
driver: local
388+
opensearch_data:
389+
driver: local
390+
391+
# Web server-specific volumes
392+
nginx_logs:
393+
driver: local
394+
caddy_data:
395+
driver: local
396+
caddy_config:
397+
driver: local

0 commit comments

Comments
 (0)