├── 4 ├── apache │ ├── Dockerfile │ ├── cron.sh │ ├── entrypoint.sh │ └── queue.sh ├── fpm-alpine │ ├── Dockerfile │ ├── cron.sh │ ├── entrypoint.sh │ └── queue.sh └── fpm │ ├── Dockerfile │ ├── cron.sh │ ├── entrypoint.sh │ └── queue.sh ├── 5 ├── apache │ ├── Dockerfile │ ├── cron.sh │ ├── entrypoint.sh │ ├── env.production │ └── queue.sh ├── fpm-alpine │ ├── Dockerfile │ ├── cron.sh │ ├── entrypoint.sh │ ├── env.production │ └── queue.sh └── fpm │ ├── Dockerfile │ ├── cron.sh │ ├── entrypoint.sh │ ├── env.production │ └── queue.sh ├── .examples ├── full │ ├── .env │ ├── app │ │ └── Dockerfile │ ├── docker-compose.yml │ └── web │ │ ├── Dockerfile │ │ └── nginx.conf ├── full_v5 │ ├── .env │ ├── app │ │ └── Dockerfile │ ├── docker-compose.yml │ └── web │ │ ├── Dockerfile │ │ └── nginx.conf ├── maxsize │ ├── .env │ ├── app │ │ └── Dockerfile │ ├── docker-compose.yml │ └── web │ │ ├── Dockerfile │ │ └── nginx.conf ├── nginx-proxy-self-signed-ssl │ ├── .env │ ├── app │ │ └── Dockerfile │ ├── docker-compose.yml │ ├── proxy │ │ ├── Dockerfile │ │ └── vhost.conf │ └── web │ │ ├── Dockerfile │ │ └── nginx.conf ├── nginx-proxy │ ├── .env │ ├── app │ │ └── Dockerfile │ ├── docker-compose.yml │ ├── proxy │ │ ├── Dockerfile │ │ └── vhost.conf │ └── web │ │ ├── Dockerfile │ │ └── nginx.conf ├── raspberrypi │ ├── .env │ └── docker-compose.yml ├── readme.md ├── simple │ ├── apache │ │ └── docker-compose.yml │ └── fpm │ │ ├── docker-compose.yml │ │ └── web │ │ ├── Dockerfile │ │ └── nginx.conf └── supervisor │ ├── apache │ ├── .env │ ├── app │ │ ├── Dockerfile │ │ └── supervisord.conf │ └── docker-compose.yml │ ├── fpm-alpine │ ├── .env │ ├── app │ │ ├── Dockerfile │ │ └── supervisord.conf │ ├── docker-compose.yml │ └── web │ │ ├── Dockerfile │ │ └── nginx.conf │ └── fpm │ ├── .env │ ├── app │ ├── Dockerfile │ └── supervisord.conf │ ├── docker-compose.yml │ └── web │ ├── Dockerfile │ └── nginx.conf ├── .gitattributes ├── .github └── workflows │ ├── build.yml │ ├── publish.yml │ └── release.yml ├── .gitignore ├── .templates ├── Dockerfile-alpine.template ├── Dockerfile-apache.template ├── Dockerfile-debian.template ├── Dockerfile-extra.template ├── Dockerfile-foot4.template ├── Dockerfile-foot5.template ├── Dockerfile-head.template ├── Dockerfile-install.template ├── Dockerfile-label.template └── scripts │ ├── 4 │ ├── cron.sh │ ├── entrypoint.sh │ └── queue.sh │ └── 5 │ ├── cron.sh │ ├── entrypoint.sh │ ├── env.production │ └── queue.sh ├── LICENSE ├── build.sh ├── generate-stackbrew-library.sh └── update.sh /.examples/full/.env: -------------------------------------------------------------------------------- 1 | APP_ENV=production 2 | APP_DEBUG=false 3 | 4 | # The URL of your application. 5 | APP_URL=http://localhost 6 | 7 | # Set trusted proxy IP addresses. 8 | # To trust all proxies that connect directly to your server, use a "*". 9 | APP_TRUSTED_PROXIES=* 10 | 11 | # Database information 12 | DB_CONNECTION=mysql 13 | DB_HOST=db 14 | DB_DATABASE=monica 15 | DB_USERNAME=monica 16 | 17 | # Mail credentials used to send emails from the application. 18 | MAIL_DRIVER=smtp 19 | MAIL_HOST=smtp.domain.com 20 | MAIL_PORT=587 21 | MAIL_USERNAME=username 22 | MAIL_PASSWORD=password 23 | MAIL_ENCRYPTION=tls 24 | # Outgoing emails will be sent with these identity 25 | MAIL_FROM_ADDRESS=email@example.com 26 | MAIL_FROM_NAME="Monica instance" 27 | 28 | LOG_CHANNEL=stderr 29 | 30 | CACHE_DRIVER=redis 31 | SESSION_DRIVER=database 32 | QUEUE_DRIVER=redis 33 | REDIS_HOST=redis 34 | -------------------------------------------------------------------------------- /.examples/full/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm-alpine 2 | 3 | # Use the default production configuration 4 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 5 | 6 | ENV PHP_UPLOAD_LIMIT="10G" 7 | -------------------------------------------------------------------------------- /.examples/full/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with fpm flavor, mariadb, cron, queue, redis, and nginx 2 | # 3 | # You first need to generate the secrets for the encryption key and db password: 4 | # `{ echo -n 'base64:'; openssl rand -base64 32; } | docker secret create app_key -` 5 | # `openssl rand -hex 24 | docker secret create mysql_password -` 6 | # 7 | # You might want to set these variables in you .env file: 8 | #- APP_URL with your domain (https scheme) 9 | # 10 | 11 | version: "3.9" 12 | 13 | services: 14 | app: &app 15 | build: ./app 16 | image: monica-app 17 | env_file: .env 18 | environment: 19 | - APP_KEY_FILE=/run/secrets/app_key 20 | - DB_PASSWORD_FILE=/run/secrets/mysql_password 21 | volumes: 22 | - data:/var/www/html/storage 23 | restart: always 24 | depends_on: 25 | - db 26 | - redis 27 | secrets: 28 | - app_key 29 | - mysql_password 30 | 31 | db: 32 | image: mariadb:11 33 | environment: 34 | - MYSQL_RANDOM_ROOT_PASSWORD=true 35 | - MYSQL_DATABASE=monica 36 | - MYSQL_USER=monica 37 | - MYSQL_PASSWORD_FILE=/run/secrets/mysql_password 38 | volumes: 39 | - mysqldata:/var/lib/mysql 40 | restart: always 41 | secrets: 42 | - mysql_password 43 | 44 | redis: 45 | image: redis:alpine 46 | restart: always 47 | 48 | cron: 49 | <<: *app 50 | command: cron.sh 51 | 52 | queue: 53 | <<: *app 54 | command: queue.sh 55 | 56 | web: 57 | build: ./web 58 | image: monica-web 59 | restart: always 60 | ports: 61 | - 80:80 62 | volumes: 63 | - data:/var/www/html/storage:ro 64 | depends_on: 65 | - app 66 | 67 | 68 | volumes: 69 | data: 70 | driver: local 71 | mysqldata: 72 | driver: local 73 | 74 | 75 | secrets: 76 | app_key: 77 | external: true 78 | mysql_password: 79 | external: true 80 | -------------------------------------------------------------------------------- /.examples/full/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm-alpine AS monica 2 | 3 | FROM nginx:alpine 4 | 5 | COPY nginx.conf /etc/nginx/nginx.conf 6 | 7 | # Copy content of monica image 8 | COPY --from=monica /var/www/html /var/www/html 9 | RUN ln -sf /var/www/html/storage/app/public /var/www/html/public/storage 10 | -------------------------------------------------------------------------------- /.examples/full/web/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log /var/log/nginx/error.log warn; 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | include /etc/nginx/mime.types; 12 | default_type application/octet-stream; 13 | 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | #tcp_nopush on; 22 | 23 | keepalive_timeout 65; 24 | 25 | set_real_ip_from 10.0.0.0/8; 26 | set_real_ip_from 172.16.0.0/12; 27 | set_real_ip_from 192.168.0.0/16; 28 | real_ip_header X-Real-IP; 29 | 30 | # Connect to app service 31 | upstream php-handler { 32 | server app:9000; 33 | } 34 | 35 | server { 36 | listen 80; 37 | 38 | server_name monica; 39 | 40 | ## HSTS ## 41 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 42 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 43 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 44 | # removed from this list could take several months. 45 | # 46 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 47 | 48 | add_header Referrer-Policy "no-referrer" always; 49 | add_header X-Content-Type-Options "nosniff" always; 50 | add_header X-Download-Options "noopen" always; 51 | add_header X-Frame-Options "SAMEORIGIN" always; 52 | add_header X-Permitted-Cross-Domain-Policies "none" always; 53 | add_header X-Robots-Tag "none" always; 54 | add_header X-XSS-Protection "1; mode=block" always; 55 | 56 | # Remove X-Powered-By, which is an information leak 57 | fastcgi_hide_header X-Powered-By; 58 | 59 | root /var/www/html/public; 60 | 61 | index index.html index.htm index.php; 62 | 63 | charset utf-8; 64 | 65 | location / { 66 | try_files $uri $uri/ /index.php?$query_string; 67 | } 68 | 69 | location ~ ^/(?:robots.txt|security.txt) { 70 | allow all; 71 | log_not_found off; 72 | access_log off; 73 | } 74 | 75 | error_page 404 500 502 503 504 /index.php; 76 | 77 | location ~ /\.well-known/(?:carddav|caldav) { 78 | return 301 $scheme://$host/dav; 79 | } 80 | location = /.well-known/security.txt { 81 | return 301 $scheme://$host/security.txt; 82 | } 83 | location ~ /\.(?!well-known).* { 84 | deny all; 85 | } 86 | 87 | # set max upload size 88 | client_max_body_size 10G; 89 | fastcgi_buffers 64 4K; 90 | 91 | # Enable gzip but do not remove ETag headers 92 | gzip on; 93 | gzip_vary on; 94 | gzip_comp_level 4; 95 | gzip_min_length 256; 96 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; 97 | gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; 98 | 99 | # Uncomment if your server is build with the ngx_pagespeed module 100 | # This module is currently not supported. 101 | #pagespeed off; 102 | 103 | location ~ \.php(/|$) { 104 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 105 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 106 | 107 | # Check that the PHP script exists before passing it 108 | try_files $fastcgi_script_name =404; 109 | 110 | fastcgi_pass php-handler; 111 | fastcgi_index index.php; 112 | 113 | include fastcgi_params; 114 | 115 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 116 | # Bypass the fact that try_files resets $fastcgi_path_info 117 | # see: http://trac.nginx.org/nginx/ticket/321 118 | set $path_info $fastcgi_path_info; 119 | fastcgi_param PATH_INFO $path_info; 120 | } 121 | 122 | # Adding the cache control header for js and css files 123 | # Make sure it is BELOW the PHP block 124 | location ~ \.(?:css|js|woff2?|svg|gif|json)$ { 125 | try_files $uri /index.php$request_uri; 126 | add_header Cache-Control "public, max-age=15778463"; 127 | 128 | ## HSTS ## 129 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 130 | # Note it is intended to have those duplicated to the ones above. 131 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 132 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 133 | # removed from this list could take several months. 134 | # 135 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 136 | 137 | add_header Referrer-Policy "no-referrer" always; 138 | add_header X-Content-Type-Options "nosniff" always; 139 | add_header X-Download-Options "noopen" always; 140 | add_header X-Frame-Options "SAMEORIGIN" always; 141 | add_header X-Permitted-Cross-Domain-Policies "none" always; 142 | add_header X-Robots-Tag "none" always; 143 | add_header X-XSS-Protection "1; mode=block" always; 144 | 145 | # Optional: Don't log access to assets 146 | access_log off; 147 | } 148 | 149 | location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ { 150 | try_files $uri /index.php$request_uri; 151 | 152 | # Optional: Don't log access to assets 153 | access_log off; 154 | } 155 | 156 | # deny access to .htaccess files 157 | location ~ /\.ht { 158 | deny all; 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /.examples/full_v5/.env: -------------------------------------------------------------------------------- 1 | # The URL of your application. 2 | APP_URL=http://localhost 3 | 4 | # Database information 5 | DB_CONNECTION=mysql 6 | DB_HOST=db 7 | DB_DATABASE=monica 8 | DB_USERNAME=monica 9 | 10 | LOG_STACK=stderr 11 | 12 | CACHE_STORE=memcached 13 | QUEUE_CONNECTION=redis 14 | SESSION_DRIVER=database 15 | REDIS_HOST=redis 16 | 17 | # Mail credentials used to send emails from the application. 18 | MAIL_MAILER=smtp 19 | MAIL_HOST=smtp.domain.com 20 | MAIL_PORT=587 21 | MAIL_USERNAME=username 22 | MAIL_PASSWORD=password 23 | MAIL_ENCRYPTION=tls 24 | # Outgoing emails will be sent with these identity 25 | MAIL_FROM_ADDRESS=hello@example.com 26 | MAIL_FROM_NAME="${APP_NAME}" 27 | MAIL_REPLY_TO_ADDRESS=hello@example.com 28 | MAIL_REPLY_TO_NAME="${APP_NAME}" 29 | 30 | SCOUT_DRIVER=meilisearch 31 | SCOUT_QUEUE=true 32 | MEILISEARCH_HOST=http://meilisearch:7700 33 | -------------------------------------------------------------------------------- /.examples/full_v5/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:5.0-fpm-alpine 2 | 3 | # Use the default production configuration 4 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 5 | 6 | ENV PHP_UPLOAD_LIMIT="10G" 7 | -------------------------------------------------------------------------------- /.examples/full_v5/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with fpm flavor, mariadb, cron, queue, redis, and nginx 2 | # 3 | # You first need to generate the secrets for the encryption key and db password: 4 | # `{ echo -n 'base64:'; openssl rand -base64 32; } | docker secret create app_key -` 5 | # `openssl rand -hex 24 | docker secret create mysql_password -` 6 | # 7 | # You might want to set these variables in you .env file: 8 | #- APP_URL with your domain (https scheme) 9 | # 10 | 11 | services: 12 | app: &app 13 | build: ./app 14 | image: monica-app 15 | env_file: .env 16 | environment: 17 | - APP_KEY_FILE=/run/secrets/app_key 18 | - DB_PASSWORD_FILE=/run/secrets/mysql_password 19 | - MEILISEARCH_KEY=ChangeMe_ChangeMe 20 | volumes: 21 | - data:/var/www/html/storage 22 | networks: 23 | - monica 24 | restart: always 25 | depends_on: 26 | - db 27 | - redis 28 | - memcached 29 | - meilisearch 30 | secrets: 31 | - app_key 32 | - mysql_password 33 | 34 | db: 35 | image: mariadb:11 36 | environment: 37 | - MYSQL_RANDOM_ROOT_PASSWORD=true 38 | - MYSQL_DATABASE=monica 39 | - MYSQL_USER=monica 40 | - MYSQL_PASSWORD_FILE=/run/secrets/mysql_password 41 | volumes: 42 | - mysqldata:/var/lib/mysql 43 | networks: 44 | - monica 45 | restart: always 46 | secrets: 47 | - mysql_password 48 | 49 | redis: 50 | image: redis:alpine 51 | restart: always 52 | networks: 53 | - monica 54 | 55 | cron: 56 | <<: *app 57 | command: cron.sh 58 | 59 | queue: 60 | <<: *app 61 | command: queue.sh 62 | 63 | memcached: 64 | image: memcached:alpine 65 | networks: 66 | - monica 67 | 68 | meilisearch: 69 | image: getmeili/meilisearch:latest 70 | environment: 71 | - MEILI_MASTER_KEY=ChangeMe_ChangeMe 72 | - MEILISEARCH_NO_ANALYTICS=true 73 | volumes: 74 | - meili_data:/meili_data 75 | networks: 76 | - monica 77 | 78 | web: 79 | build: ./web 80 | image: monica-web 81 | restart: always 82 | ports: 83 | - 80:80 84 | volumes: 85 | - data:/var/www/html/storage:ro 86 | networks: 87 | - monica 88 | depends_on: 89 | - app 90 | 91 | 92 | networks: 93 | monica: 94 | driver: overlay 95 | 96 | 97 | volumes: 98 | data: 99 | driver: local 100 | mysqldata: 101 | driver: local 102 | meili_data: 103 | driver: local 104 | 105 | 106 | secrets: 107 | app_key: 108 | external: true 109 | mysql_password: 110 | external: true 111 | -------------------------------------------------------------------------------- /.examples/full_v5/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:5.0-fpm-alpine AS monica 2 | 3 | FROM nginx:alpine 4 | 5 | COPY nginx.conf /etc/nginx/nginx.conf 6 | 7 | # Copy content of monica image 8 | COPY --from=monica /var/www/html /var/www/html 9 | RUN ln -sf /var/www/html/storage/app/public /var/www/html/public/storage 10 | -------------------------------------------------------------------------------- /.examples/full_v5/web/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log /var/log/nginx/error.log warn; 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | include /etc/nginx/mime.types; 12 | default_type application/octet-stream; 13 | 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | #tcp_nopush on; 22 | 23 | keepalive_timeout 65; 24 | 25 | set_real_ip_from 10.0.0.0/8; 26 | set_real_ip_from 172.16.0.0/12; 27 | set_real_ip_from 192.168.0.0/16; 28 | real_ip_header X-Real-IP; 29 | 30 | # Connect to app service 31 | upstream php-handler { 32 | server app:9000; 33 | } 34 | 35 | server { 36 | listen 80; 37 | 38 | server_name monica; 39 | 40 | ## HSTS ## 41 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 42 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 43 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 44 | # removed from this list could take several months. 45 | # 46 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 47 | 48 | add_header Referrer-Policy "no-referrer" always; 49 | add_header X-Content-Type-Options "nosniff" always; 50 | add_header X-Download-Options "noopen" always; 51 | add_header X-Frame-Options "SAMEORIGIN" always; 52 | add_header X-Permitted-Cross-Domain-Policies "none" always; 53 | add_header X-Robots-Tag "none" always; 54 | add_header X-XSS-Protection "1; mode=block" always; 55 | 56 | # Remove X-Powered-By, which is an information leak 57 | fastcgi_hide_header X-Powered-By; 58 | 59 | root /var/www/html/public; 60 | 61 | index index.html index.htm index.php; 62 | 63 | charset utf-8; 64 | 65 | location / { 66 | try_files $uri $uri/ /index.php?$query_string; 67 | } 68 | 69 | location ~ ^/(?:robots.txt|security.txt) { 70 | allow all; 71 | log_not_found off; 72 | access_log off; 73 | } 74 | 75 | error_page 404 500 502 503 504 /index.php; 76 | 77 | location ~ /\.well-known/(?:carddav|caldav) { 78 | return 301 $scheme://$host/dav; 79 | } 80 | location = /.well-known/security.txt { 81 | return 301 $scheme://$host/security.txt; 82 | } 83 | location ~ /\.(?!well-known).* { 84 | deny all; 85 | } 86 | 87 | # set max upload size 88 | client_max_body_size 10G; 89 | fastcgi_buffers 64 4K; 90 | 91 | # Enable gzip but do not remove ETag headers 92 | gzip on; 93 | gzip_vary on; 94 | gzip_comp_level 4; 95 | gzip_min_length 256; 96 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; 97 | gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; 98 | 99 | # Uncomment if your server is build with the ngx_pagespeed module 100 | # This module is currently not supported. 101 | #pagespeed off; 102 | 103 | location ~ \.php(/|$) { 104 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 105 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 106 | 107 | # Check that the PHP script exists before passing it 108 | try_files $fastcgi_script_name =404; 109 | 110 | fastcgi_pass php-handler; 111 | fastcgi_index index.php; 112 | 113 | include fastcgi_params; 114 | 115 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 116 | # Bypass the fact that try_files resets $fastcgi_path_info 117 | # see: http://trac.nginx.org/nginx/ticket/321 118 | set $path_info $fastcgi_path_info; 119 | fastcgi_param PATH_INFO $path_info; 120 | } 121 | 122 | # Adding the cache control header for js and css files 123 | # Make sure it is BELOW the PHP block 124 | location ~ \.(?:css|js|woff2?|svg|gif|json)$ { 125 | try_files $uri /index.php$request_uri; 126 | add_header Cache-Control "public, max-age=15778463"; 127 | 128 | ## HSTS ## 129 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 130 | # Note it is intended to have those duplicated to the ones above. 131 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 132 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 133 | # removed from this list could take several months. 134 | # 135 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 136 | 137 | add_header Referrer-Policy "no-referrer" always; 138 | add_header X-Content-Type-Options "nosniff" always; 139 | add_header X-Download-Options "noopen" always; 140 | add_header X-Frame-Options "SAMEORIGIN" always; 141 | add_header X-Permitted-Cross-Domain-Policies "none" always; 142 | add_header X-Robots-Tag "none" always; 143 | add_header X-XSS-Protection "1; mode=block" always; 144 | 145 | # Optional: Don't log access to assets 146 | access_log off; 147 | } 148 | 149 | location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ { 150 | try_files $uri /index.php$request_uri; 151 | 152 | # Optional: Don't log access to assets 153 | access_log off; 154 | } 155 | 156 | # deny access to .htaccess files 157 | location ~ /\.ht { 158 | deny all; 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /.examples/maxsize/.env: -------------------------------------------------------------------------------- 1 | APP_ENV=production 2 | APP_DEBUG=false 3 | 4 | # The encryption key. Must be 32 characters long exactly. 5 | # Use `echo -n 'base64:'; openssl rand -base64 32` to generate a random key. 6 | # APP_KEY= 7 | 8 | # The URL of your application. 9 | APP_URL=http://localhost 10 | 11 | # Set trusted proxy IP addresses. 12 | # To trust all proxies that connect directly to your server, use a "*". 13 | APP_TRUSTED_PROXIES= 14 | 15 | # Database information 16 | DB_CONNECTION=mysql 17 | DB_HOST=db 18 | DB_DATABASE=monica 19 | DB_USERNAME=monica 20 | DB_PASSWORD=secret 21 | 22 | # Mail credentials used to send emails from the application. 23 | MAIL_DRIVER=smtp 24 | MAIL_HOST=smtp.domain.com 25 | MAIL_PORT=587 26 | MAIL_USERNAME=username 27 | MAIL_PASSWORD=password 28 | MAIL_ENCRYPTION=tls 29 | # Outgoing emails will be sent with these identity 30 | MAIL_FROM_ADDRESS=email@example.com 31 | MAIL_FROM_NAME="Monica instance" 32 | 33 | LOG_CHANNEL=stderr 34 | 35 | CACHE_DRIVER=database 36 | SESSION_DRIVER=database 37 | QUEUE_DRIVER=sync 38 | 39 | DEFAULT_MAX_UPLOAD_SIZE=500000 40 | -------------------------------------------------------------------------------- /.examples/maxsize/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm-alpine 2 | 3 | # Use the default production configuration 4 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 5 | 6 | # Set the upload limit to 10G 7 | ENV PHP_UPLOAD_LIMIT="10G" 8 | 9 | # Set the memory limit to 512M 10 | ENV PHP_MEMORY_LIMIT="512M" 11 | -------------------------------------------------------------------------------- /.examples/maxsize/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with nginx proxy and specific file size limits 2 | # 3 | # You might want to set these variables in you .env file: 4 | # 5 | #- APP_ENV=production 6 | #- APP_URL with your domain (https scheme) 7 | #- APP_KEY with a random string 8 | # 9 | #- DB_HOST=db 10 | # See `db` container for these values: 11 | #- DB_DATABASE=monica 12 | #- DB_USERNAME=monica 13 | #- DB_PASSWORD=secret 14 | # 15 | # Also set this to the appropriate limit: 16 | #- DEFAULT_MAX_UPLOAD_SIZE=500000 17 | # 18 | 19 | version: "3.9" 20 | 21 | services: 22 | app: 23 | build: ./app 24 | image: monica-app 25 | env_file: .env 26 | depends_on: 27 | - db 28 | volumes: 29 | - data:/var/www/html/storage 30 | restart: always 31 | 32 | web: 33 | build: ./web 34 | image: monica-web 35 | restart: always 36 | ports: 37 | - 80:80 38 | volumes: 39 | - data:/var/www/html/storage:ro 40 | depends_on: 41 | - app 42 | 43 | db: 44 | image: mariadb:11 45 | environment: 46 | - MYSQL_RANDOM_ROOT_PASSWORD=true 47 | - MYSQL_DATABASE=monica 48 | - MYSQL_USER=monica 49 | - MYSQL_PASSWORD=secret 50 | volumes: 51 | - mysqldata:/var/lib/mysql 52 | restart: always 53 | 54 | 55 | volumes: 56 | data: 57 | driver: local 58 | mysqldata: 59 | driver: local 60 | -------------------------------------------------------------------------------- /.examples/maxsize/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm-alpine AS monica 2 | 3 | FROM nginx:alpine 4 | 5 | COPY nginx.conf /etc/nginx/nginx.conf 6 | 7 | # Copy content of monica image 8 | COPY --from=monica /var/www/html /var/www/html 9 | RUN ln -sf /var/www/html/storage/app/public /var/www/html/public/storage 10 | -------------------------------------------------------------------------------- /.examples/maxsize/web/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log /var/log/nginx/error.log warn; 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | include /etc/nginx/mime.types; 12 | default_type application/octet-stream; 13 | 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | #tcp_nopush on; 22 | 23 | keepalive_timeout 65; 24 | 25 | set_real_ip_from 10.0.0.0/8; 26 | set_real_ip_from 172.16.0.0/12; 27 | set_real_ip_from 192.168.0.0/16; 28 | real_ip_header X-Real-IP; 29 | 30 | # Connect to app service 31 | upstream php-handler { 32 | server app:9000; 33 | } 34 | 35 | server { 36 | listen 80; 37 | 38 | server_name monica; 39 | 40 | ## HSTS ## 41 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 42 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 43 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 44 | # removed from this list could take several months. 45 | # 46 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 47 | 48 | add_header Referrer-Policy "no-referrer" always; 49 | add_header X-Content-Type-Options "nosniff" always; 50 | add_header X-Download-Options "noopen" always; 51 | add_header X-Frame-Options "SAMEORIGIN" always; 52 | add_header X-Permitted-Cross-Domain-Policies "none" always; 53 | add_header X-Robots-Tag "none" always; 54 | add_header X-XSS-Protection "1; mode=block" always; 55 | 56 | # Remove X-Powered-By, which is an information leak 57 | fastcgi_hide_header X-Powered-By; 58 | 59 | root /var/www/html/public; 60 | 61 | index index.html index.htm index.php; 62 | 63 | charset utf-8; 64 | 65 | location / { 66 | try_files $uri $uri/ /index.php?$query_string; 67 | } 68 | 69 | location ~ ^/(?:robots.txt|security.txt) { 70 | allow all; 71 | log_not_found off; 72 | access_log off; 73 | } 74 | 75 | error_page 404 500 502 503 504 /index.php; 76 | 77 | location ~ /\.well-known/(?:carddav|caldav) { 78 | return 301 $scheme://$host/dav; 79 | } 80 | location = /.well-known/security.txt { 81 | return 301 $scheme://$host/security.txt; 82 | } 83 | location ~ /\.(?!well-known).* { 84 | deny all; 85 | } 86 | 87 | # set max upload size 88 | client_max_body_size 10G; 89 | fastcgi_buffers 64 4K; 90 | 91 | # Enable gzip but do not remove ETag headers 92 | gzip on; 93 | gzip_vary on; 94 | gzip_comp_level 4; 95 | gzip_min_length 256; 96 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; 97 | gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; 98 | 99 | # Uncomment if your server is build with the ngx_pagespeed module 100 | # This module is currently not supported. 101 | #pagespeed off; 102 | 103 | location ~ \.php(/|$) { 104 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 105 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 106 | 107 | # Check that the PHP script exists before passing it 108 | try_files $fastcgi_script_name =404; 109 | 110 | fastcgi_pass php-handler; 111 | fastcgi_index index.php; 112 | 113 | include fastcgi_params; 114 | 115 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 116 | # Bypass the fact that try_files resets $fastcgi_path_info 117 | # see: http://trac.nginx.org/nginx/ticket/321 118 | set $path_info $fastcgi_path_info; 119 | fastcgi_param PATH_INFO $path_info; 120 | } 121 | 122 | # Adding the cache control header for js and css files 123 | # Make sure it is BELOW the PHP block 124 | location ~ \.(?:css|js|woff2?|svg|gif|json)$ { 125 | try_files $uri /index.php$request_uri; 126 | add_header Cache-Control "public, max-age=15778463"; 127 | 128 | ## HSTS ## 129 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 130 | # Note it is intended to have those duplicated to the ones above. 131 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 132 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 133 | # removed from this list could take several months. 134 | # 135 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 136 | 137 | add_header Referrer-Policy "no-referrer" always; 138 | add_header X-Content-Type-Options "nosniff" always; 139 | add_header X-Download-Options "noopen" always; 140 | add_header X-Frame-Options "SAMEORIGIN" always; 141 | add_header X-Permitted-Cross-Domain-Policies "none" always; 142 | add_header X-Robots-Tag "none" always; 143 | add_header X-XSS-Protection "1; mode=block" always; 144 | 145 | # Optional: Don't log access to assets 146 | access_log off; 147 | } 148 | 149 | location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ { 150 | try_files $uri /index.php$request_uri; 151 | 152 | # Optional: Don't log access to assets 153 | access_log off; 154 | } 155 | 156 | # deny access to .htaccess files 157 | location ~ /\.ht { 158 | deny all; 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /.examples/nginx-proxy-self-signed-ssl/.env: -------------------------------------------------------------------------------- 1 | APP_ENV=production 2 | APP_DEBUG=false 3 | 4 | # The encryption key. Must be 32 characters long exactly. 5 | # Use `echo -n 'base64:'; openssl rand -base64 32` to generate a random key. 6 | # APP_KEY= 7 | 8 | # The URL of your application. 9 | APP_URL=https://localhost 10 | 11 | # Set trusted proxy IP addresses. 12 | # To trust all proxies that connect directly to your server, use a "*". 13 | APP_TRUSTED_PROXIES=* 14 | 15 | # Database information 16 | DB_CONNECTION=mysql 17 | DB_HOST=db 18 | DB_DATABASE=monica 19 | DB_USERNAME=monica 20 | DB_PASSWORD=secret 21 | 22 | # Mail credentials used to send emails from the application. 23 | MAIL_DRIVER=smtp 24 | MAIL_HOST=smtp.domain.com 25 | MAIL_PORT=587 26 | MAIL_USERNAME=username 27 | MAIL_PASSWORD=password 28 | MAIL_ENCRYPTION=tls 29 | # Outgoing emails will be sent with these identity 30 | MAIL_FROM_ADDRESS=email@example.com 31 | MAIL_FROM_NAME="Monica instance" 32 | 33 | LOG_CHANNEL=stderr 34 | 35 | CACHE_DRIVER=redis 36 | SESSION_DRIVER=database 37 | QUEUE_DRIVER=redis 38 | REDIS_HOST=redis 39 | -------------------------------------------------------------------------------- /.examples/nginx-proxy-self-signed-ssl/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm 2 | 3 | # Use the default production configuration 4 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 5 | 6 | ENV PHP_UPLOAD_LIMIT="10G" 7 | -------------------------------------------------------------------------------- /.examples/nginx-proxy-self-signed-ssl/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with a self-signed-ssl certificate 2 | # 3 | # You might want to set these variables in you .env file: 4 | # 5 | #- APP_ENV=production 6 | #- APP_URL with your domain (https scheme) 7 | #- APP_KEY with a random string 8 | #- APP_TRUSTED_PROXIES=* 9 | # 10 | # If you're not using default 443 port for https, set APP_URL and: 11 | #- APP_FORCE_URL=true 12 | # 13 | #- DB_HOST=db 14 | # See `db` container for these values: 15 | #- DB_DATABASE=monica 16 | #- DB_USERNAME=monica 17 | #- DB_PASSWORD=secret 18 | # 19 | # To use redis: 20 | #- REDIS_HOST=redis 21 | #- CACHE_DRIVER=redis 22 | #- QUEUE_DRIVER=redis 23 | # 24 | 25 | version: "3.9" 26 | 27 | services: 28 | app: &app 29 | build: ./app 30 | image: monica-app 31 | env_file: .env 32 | volumes: 33 | - data:/var/www/html/storage 34 | restart: always 35 | depends_on: 36 | - db 37 | - redis 38 | 39 | db: 40 | image: mariadb:11 41 | environment: 42 | - MYSQL_RANDOM_ROOT_PASSWORD=true 43 | - MYSQL_DATABASE=monica 44 | - MYSQL_USER=monica 45 | - MYSQL_PASSWORD=secret 46 | volumes: 47 | - mysqldata:/var/lib/mysql 48 | restart: always 49 | 50 | redis: 51 | image: redis:alpine 52 | restart: always 53 | 54 | cron: 55 | <<: *app 56 | command: cron.sh 57 | 58 | queue: 59 | <<: *app 60 | command: queue.sh 61 | 62 | web: 63 | build: ./web 64 | image: monica-web 65 | restart: always 66 | environment: 67 | - VIRTUAL_HOST=monica.local 68 | volumes: 69 | - data:/var/www/html/storage:ro 70 | depends_on: 71 | - app 72 | networks: 73 | - proxy-tier 74 | - default 75 | 76 | proxy: 77 | build: ./proxy 78 | restart: always 79 | ports: 80 | - 80:80 81 | - 443:443 82 | volumes: 83 | - certs:/etc/nginx/certs:ro 84 | - /var/run/docker.sock:/tmp/docker.sock:ro 85 | networks: 86 | - proxy-tier 87 | depends_on: 88 | - omgwtfssl 89 | 90 | omgwtfssl: 91 | image: paulczar/omgwtfssl 92 | restart: "no" 93 | volumes: 94 | - certs:/certs 95 | environment: 96 | - SSL_SUBJECT=monica.local 97 | - CA_SUBJECT=my@example.com 98 | - SSL_KEY=/certs/monica.local.key 99 | - SSL_CSR=/certs/monica.local.csr 100 | - SSL_CERT=/certs/monica.local.crt 101 | networks: 102 | - proxy-tier 103 | 104 | 105 | networks: 106 | proxy-tier: 107 | driver: bridge 108 | 109 | 110 | volumes: 111 | data: 112 | driver: local 113 | mysqldata: 114 | driver: local 115 | certs: 116 | driver: local 117 | -------------------------------------------------------------------------------- /.examples/nginx-proxy-self-signed-ssl/proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jwilder/nginx-proxy:alpine 2 | 3 | COPY vhost.conf /etc/nginx/vhost.d/default 4 | -------------------------------------------------------------------------------- /.examples/nginx-proxy-self-signed-ssl/proxy/vhost.conf: -------------------------------------------------------------------------------- 1 | client_max_body_size 10G; 2 | server_tokens off; -------------------------------------------------------------------------------- /.examples/nginx-proxy-self-signed-ssl/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm AS monica 2 | 3 | FROM nginx:alpine 4 | 5 | COPY nginx.conf /etc/nginx/nginx.conf 6 | 7 | # Copy content of monica image 8 | COPY --from=monica /var/www/html /var/www/html 9 | RUN ln -sf /var/www/html/storage/app/public /var/www/html/public/storage 10 | -------------------------------------------------------------------------------- /.examples/nginx-proxy-self-signed-ssl/web/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log /var/log/nginx/error.log warn; 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | include /etc/nginx/mime.types; 12 | default_type application/octet-stream; 13 | 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | #tcp_nopush on; 22 | 23 | keepalive_timeout 65; 24 | 25 | set_real_ip_from 10.0.0.0/8; 26 | set_real_ip_from 172.16.0.0/12; 27 | set_real_ip_from 192.168.0.0/16; 28 | real_ip_header X-Real-IP; 29 | 30 | # Connect to app service 31 | upstream php-handler { 32 | server app:9000; 33 | } 34 | 35 | server { 36 | listen 80; 37 | 38 | server_name monica; 39 | 40 | ## HSTS ## 41 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 42 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 43 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 44 | # removed from this list could take several months. 45 | # 46 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 47 | 48 | add_header Referrer-Policy "no-referrer" always; 49 | add_header X-Content-Type-Options "nosniff" always; 50 | add_header X-Download-Options "noopen" always; 51 | add_header X-Frame-Options "SAMEORIGIN" always; 52 | add_header X-Permitted-Cross-Domain-Policies "none" always; 53 | add_header X-Robots-Tag "none" always; 54 | add_header X-XSS-Protection "1; mode=block" always; 55 | 56 | # Remove X-Powered-By, which is an information leak 57 | fastcgi_hide_header X-Powered-By; 58 | 59 | root /var/www/html/public; 60 | 61 | index index.html index.htm index.php; 62 | 63 | charset utf-8; 64 | 65 | location / { 66 | try_files $uri $uri/ /index.php?$query_string; 67 | } 68 | 69 | location ~ ^/(?:robots.txt|security.txt) { 70 | allow all; 71 | log_not_found off; 72 | access_log off; 73 | } 74 | 75 | error_page 404 500 502 503 504 /index.php; 76 | 77 | location ~ /\.well-known/(?:carddav|caldav) { 78 | return 301 $scheme://$host/dav; 79 | } 80 | location = /.well-known/security.txt { 81 | return 301 $scheme://$host/security.txt; 82 | } 83 | location ~ /\.(?!well-known).* { 84 | deny all; 85 | } 86 | 87 | # set max upload size 88 | client_max_body_size 10G; 89 | fastcgi_buffers 64 4K; 90 | 91 | # Enable gzip but do not remove ETag headers 92 | gzip on; 93 | gzip_vary on; 94 | gzip_comp_level 4; 95 | gzip_min_length 256; 96 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; 97 | gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; 98 | 99 | # Uncomment if your server is build with the ngx_pagespeed module 100 | # This module is currently not supported. 101 | #pagespeed off; 102 | 103 | location ~ \.php(/|$) { 104 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 105 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 106 | 107 | # Check that the PHP script exists before passing it 108 | try_files $fastcgi_script_name =404; 109 | 110 | fastcgi_pass php-handler; 111 | fastcgi_index index.php; 112 | 113 | include fastcgi_params; 114 | 115 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 116 | # Bypass the fact that try_files resets $fastcgi_path_info 117 | # see: http://trac.nginx.org/nginx/ticket/321 118 | set $path_info $fastcgi_path_info; 119 | fastcgi_param PATH_INFO $path_info; 120 | } 121 | 122 | # Adding the cache control header for js and css files 123 | # Make sure it is BELOW the PHP block 124 | location ~ \.(?:css|js|woff2?|svg|gif|json)$ { 125 | try_files $uri /index.php$request_uri; 126 | add_header Cache-Control "public, max-age=15778463"; 127 | 128 | ## HSTS ## 129 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 130 | # Note it is intended to have those duplicated to the ones above. 131 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 132 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 133 | # removed from this list could take several months. 134 | # 135 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 136 | 137 | add_header Referrer-Policy "no-referrer" always; 138 | add_header X-Content-Type-Options "nosniff" always; 139 | add_header X-Download-Options "noopen" always; 140 | add_header X-Frame-Options "SAMEORIGIN" always; 141 | add_header X-Permitted-Cross-Domain-Policies "none" always; 142 | add_header X-Robots-Tag "none" always; 143 | add_header X-XSS-Protection "1; mode=block" always; 144 | 145 | # Optional: Don't log access to assets 146 | access_log off; 147 | } 148 | 149 | location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ { 150 | try_files $uri /index.php$request_uri; 151 | 152 | # Optional: Don't log access to assets 153 | access_log off; 154 | } 155 | 156 | # deny access to .htaccess files 157 | location ~ /\.ht { 158 | deny all; 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /.examples/nginx-proxy/.env: -------------------------------------------------------------------------------- 1 | APP_ENV=production 2 | APP_DEBUG=false 3 | 4 | # The encryption key. Must be 32 characters long exactly. 5 | # Use `echo -n 'base64:'; openssl rand -base64 32` to generate a random key. 6 | # APP_KEY= 7 | 8 | # The URL of your application. 9 | APP_URL=http://localhost 10 | 11 | # Set trusted proxy IP addresses. 12 | # To trust all proxies that connect directly to your server, use a "*". 13 | APP_TRUSTED_PROXIES= 14 | 15 | # Database information 16 | DB_CONNECTION=mysql 17 | DB_HOST=db 18 | DB_DATABASE=monica 19 | DB_USERNAME=monica 20 | DB_PASSWORD=secret 21 | 22 | # Mail credentials used to send emails from the application. 23 | MAIL_DRIVER=smtp 24 | MAIL_HOST=smtp.domain.com 25 | MAIL_PORT=587 26 | MAIL_USERNAME=username 27 | MAIL_PASSWORD=password 28 | MAIL_ENCRYPTION=tls 29 | # Outgoing emails will be sent with these identity 30 | MAIL_FROM_ADDRESS=email@example.com 31 | MAIL_FROM_NAME="Monica instance" 32 | 33 | LOG_CHANNEL=stderr 34 | 35 | CACHE_DRIVER=redis 36 | SESSION_DRIVER=database 37 | QUEUE_DRIVER=redis 38 | REDIS_HOST=redis 39 | -------------------------------------------------------------------------------- /.examples/nginx-proxy/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm 2 | 3 | # Use the default production configuration 4 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 5 | 6 | ENV PHP_UPLOAD_LIMIT="10G" 7 | -------------------------------------------------------------------------------- /.examples/nginx-proxy/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with nginx proxy 2 | # 3 | # You might want to set these variables in you .env file: 4 | # 5 | #- APP_ENV=production 6 | #- APP_URL with your domain (https scheme) 7 | #- APP_KEY with a random string 8 | # 9 | #- DB_HOST=db 10 | # See `db` container for these values: 11 | #- DB_DATABASE=monica 12 | #- DB_USERNAME=monica 13 | #- DB_PASSWORD=secret 14 | # 15 | # To use redis: 16 | #- REDIS_HOST=redis 17 | #- CACHE_DRIVER=redis 18 | #- QUEUE_CONNECTION=redis 19 | # 20 | 21 | version: "3.9" 22 | 23 | services: 24 | app: &app 25 | build: ./app 26 | image: monica-app 27 | env_file: .env 28 | volumes: 29 | - data:/var/www/html/storage 30 | restart: always 31 | depends_on: 32 | - db 33 | - redis 34 | 35 | db: 36 | image: mariadb:11 37 | environment: 38 | - MYSQL_RANDOM_ROOT_PASSWORD=true 39 | - MYSQL_DATABASE=monica 40 | - MYSQL_USER=monica 41 | - MYSQL_PASSWORD=secret 42 | volumes: 43 | - mysqldata:/var/lib/mysql 44 | restart: always 45 | 46 | redis: 47 | image: redis:alpine 48 | restart: always 49 | 50 | cron: 51 | <<: *app 52 | command: cron.sh 53 | 54 | queue: 55 | <<: *app 56 | command: queue.sh 57 | 58 | web: 59 | build: ./web 60 | image: monica-web 61 | restart: always 62 | environment: 63 | - VIRTUAL_HOST= 64 | - LETSENCRYPT_HOST= 65 | - LETSENCRYPT_EMAIL= 66 | volumes: 67 | - data:/var/www/html/storage:ro 68 | depends_on: 69 | - app 70 | networks: 71 | - proxy-tier 72 | - default 73 | 74 | proxy: 75 | build: ./proxy 76 | restart: always 77 | ports: 78 | - 80:80 79 | - 443:443 80 | labels: 81 | com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true" 82 | volumes: 83 | - certs:/etc/nginx/certs:ro 84 | - vhost.d:/etc/nginx/vhost.d 85 | - html:/usr/share/nginx/html 86 | - /var/run/docker.sock:/tmp/docker.sock:ro 87 | networks: 88 | - proxy-tier 89 | 90 | letsencrypt-companion: 91 | image: jrcs/letsencrypt-nginx-proxy-companion 92 | restart: always 93 | volumes: 94 | - certs:/etc/nginx/certs 95 | - vhost.d:/etc/nginx/vhost.d 96 | - html:/usr/share/nginx/html 97 | - /var/run/docker.sock:/var/run/docker.sock:ro 98 | networks: 99 | - proxy-tier 100 | depends_on: 101 | - proxy 102 | 103 | 104 | networks: 105 | proxy-tier: 106 | driver: bridge 107 | 108 | 109 | volumes: 110 | data: 111 | driver: local 112 | mysqldata: 113 | driver: local 114 | certs: 115 | driver: local 116 | vhost.d: 117 | driver: local 118 | html: 119 | driver: local 120 | -------------------------------------------------------------------------------- /.examples/nginx-proxy/proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jwilder/nginx-proxy:alpine 2 | 3 | COPY vhost.conf /etc/nginx/vhost.d/default 4 | -------------------------------------------------------------------------------- /.examples/nginx-proxy/proxy/vhost.conf: -------------------------------------------------------------------------------- 1 | client_max_body_size 10G; 2 | server_tokens off; -------------------------------------------------------------------------------- /.examples/nginx-proxy/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm AS monica 2 | 3 | FROM nginx:alpine 4 | 5 | COPY nginx.conf /etc/nginx/nginx.conf 6 | 7 | # Copy content of monica image 8 | COPY --from=monica /var/www/html /var/www/html 9 | RUN ln -sf /var/www/html/storage/app/public /var/www/html/public/storage 10 | -------------------------------------------------------------------------------- /.examples/nginx-proxy/web/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log /var/log/nginx/error.log warn; 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | include /etc/nginx/mime.types; 12 | default_type application/octet-stream; 13 | 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | #tcp_nopush on; 22 | 23 | keepalive_timeout 65; 24 | 25 | set_real_ip_from 10.0.0.0/8; 26 | set_real_ip_from 172.16.0.0/12; 27 | set_real_ip_from 192.168.0.0/16; 28 | real_ip_header X-Real-IP; 29 | 30 | # Connect to app service 31 | upstream php-handler { 32 | server app:9000; 33 | } 34 | 35 | server { 36 | listen 80; 37 | 38 | server_name monica; 39 | 40 | ## HSTS ## 41 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 42 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 43 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 44 | # removed from this list could take several months. 45 | # 46 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 47 | 48 | add_header Referrer-Policy "no-referrer" always; 49 | add_header X-Content-Type-Options "nosniff" always; 50 | add_header X-Download-Options "noopen" always; 51 | add_header X-Frame-Options "SAMEORIGIN" always; 52 | add_header X-Permitted-Cross-Domain-Policies "none" always; 53 | add_header X-Robots-Tag "none" always; 54 | add_header X-XSS-Protection "1; mode=block" always; 55 | 56 | # Remove X-Powered-By, which is an information leak 57 | fastcgi_hide_header X-Powered-By; 58 | 59 | root /var/www/html/public; 60 | 61 | index index.html index.htm index.php; 62 | 63 | charset utf-8; 64 | 65 | location / { 66 | try_files $uri $uri/ /index.php?$query_string; 67 | } 68 | 69 | location ~ ^/(?:robots.txt|security.txt) { 70 | allow all; 71 | log_not_found off; 72 | access_log off; 73 | } 74 | 75 | error_page 404 500 502 503 504 /index.php; 76 | 77 | location ~ /\.well-known/(?:carddav|caldav) { 78 | return 301 $scheme://$host/dav; 79 | } 80 | location = /.well-known/security.txt { 81 | return 301 $scheme://$host/security.txt; 82 | } 83 | location ~ /\.(?!well-known).* { 84 | deny all; 85 | } 86 | 87 | # set max upload size 88 | client_max_body_size 10G; 89 | fastcgi_buffers 64 4K; 90 | 91 | # Enable gzip but do not remove ETag headers 92 | gzip on; 93 | gzip_vary on; 94 | gzip_comp_level 4; 95 | gzip_min_length 256; 96 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; 97 | gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; 98 | 99 | # Uncomment if your server is build with the ngx_pagespeed module 100 | # This module is currently not supported. 101 | #pagespeed off; 102 | 103 | location ~ \.php(/|$) { 104 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 105 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 106 | 107 | # Check that the PHP script exists before passing it 108 | try_files $fastcgi_script_name =404; 109 | 110 | fastcgi_pass php-handler; 111 | fastcgi_index index.php; 112 | 113 | include fastcgi_params; 114 | 115 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 116 | # Bypass the fact that try_files resets $fastcgi_path_info 117 | # see: http://trac.nginx.org/nginx/ticket/321 118 | set $path_info $fastcgi_path_info; 119 | fastcgi_param PATH_INFO $path_info; 120 | } 121 | 122 | # Adding the cache control header for js and css files 123 | # Make sure it is BELOW the PHP block 124 | location ~ \.(?:css|js|woff2?|svg|gif|json)$ { 125 | try_files $uri /index.php$request_uri; 126 | add_header Cache-Control "public, max-age=15778463"; 127 | 128 | ## HSTS ## 129 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 130 | # Note it is intended to have those duplicated to the ones above. 131 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 132 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 133 | # removed from this list could take several months. 134 | # 135 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 136 | 137 | add_header Referrer-Policy "no-referrer" always; 138 | add_header X-Content-Type-Options "nosniff" always; 139 | add_header X-Download-Options "noopen" always; 140 | add_header X-Frame-Options "SAMEORIGIN" always; 141 | add_header X-Permitted-Cross-Domain-Policies "none" always; 142 | add_header X-Robots-Tag "none" always; 143 | add_header X-XSS-Protection "1; mode=block" always; 144 | 145 | # Optional: Don't log access to assets 146 | access_log off; 147 | } 148 | 149 | location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ { 150 | try_files $uri /index.php$request_uri; 151 | 152 | # Optional: Don't log access to assets 153 | access_log off; 154 | } 155 | 156 | # deny access to .htaccess files 157 | location ~ /\.ht { 158 | deny all; 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /.examples/raspberrypi/.env: -------------------------------------------------------------------------------- 1 | APP_ENV=production 2 | APP_DEBUG=false 3 | 4 | # The encryption key. Must be 32 characters long exactly. 5 | # Use `echo -n 'base64:'; openssl rand -base64 32` to generate a random key. 6 | # APP_KEY= 7 | 8 | # The URL of your application. 9 | APP_URL=http://localhost 10 | 11 | # Set trusted proxy IP addresses. 12 | # To trust all proxies that connect directly to your server, use a "*". 13 | APP_TRUSTED_PROXIES= 14 | 15 | # Database information 16 | DB_CONNECTION=mysql 17 | DB_HOST=db 18 | DB_DATABASE=monica 19 | DB_USERNAME=homestead 20 | DB_PASSWORD=secret 21 | 22 | # Mail credentials used to send emails from the application. 23 | MAIL_DRIVER=smtp 24 | MAIL_HOST=smtp.domain.com 25 | MAIL_PORT=587 26 | MAIL_USERNAME=username 27 | MAIL_PASSWORD=password 28 | MAIL_ENCRYPTION=tls 29 | # Outgoing emails will be sent with these identity 30 | MAIL_FROM_ADDRESS=email@example.com 31 | MAIL_FROM_NAME="Monica instance" 32 | 33 | LOG_CHANNEL=stderr 34 | 35 | CACHE_DRIVER=database 36 | SESSION_DRIVER=database 37 | QUEUE_DRIVER=sync 38 | -------------------------------------------------------------------------------- /.examples/raspberrypi/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | app: 5 | image: monica 6 | env_file: .env 7 | depends_on: 8 | - db 9 | ports: 10 | - 8080:80 11 | volumes: 12 | - data:/var/www/html/storage 13 | restart: always 14 | 15 | cron: 16 | image: monica 17 | env_file: .env 18 | restart: always 19 | volumes: 20 | - data:/var/www/html/storage 21 | command: cron.sh 22 | depends_on: 23 | - db 24 | 25 | db: 26 | image: jsurf/rpi-mariadb:latest 27 | environment: 28 | MYSQL_ROOT_PASSWORD: secret 29 | MYSQL_DATABASE: monica 30 | MYSQL_USER: homestead 31 | MYSQL_PASSWORD: secret 32 | volumes: 33 | - mysqldata:/var/lib/mysql 34 | restart: always 35 | 36 | 37 | volumes: 38 | data: 39 | driver: local 40 | mysqldata: 41 | driver: local 42 | -------------------------------------------------------------------------------- /.examples/readme.md: -------------------------------------------------------------------------------- 1 | # Docker examples for Monica 2 | 3 | In this section you will find some examples about how to use monica's docker images. 4 | 5 | | Example | Description | 6 | |---------|-------------| 7 | | [`simple`](simple) | simple example that run a container. 8 | | [`full`](full) | example that run `fpm-alpine` with nginx, redis, separate cron and queue containers, and uses secrets. 9 | | [`full_v5`](full_v5) | example for v5 of monica (a.k.a chandler) that run `fpm-alpine` with nginx, redis, separate cron and queue containers, and uses secrets. 10 | | [`supervisor`](supervisor) | uses supervisor to run a cron and a queue inside your container. 11 | | [`nginx-proxy-self-signed-ssl`](nginx-proxy-self-signed-ssl) | shows you how to run monica with a self signed ssl certificate. 12 | | [`nginx-proxy`](nginx-proxy) | shows you how to run monica with https and generate a [Let's Encrypt](https://letsencrypt.org/) certificate. 13 | | [`maxsize`](maxsize) | shows you how to adapt the max upload size of you php settings in the app container. 14 | | [`raspberrypi`](raspberrypi) | shows you how to host monica on a raspberry pi. 15 | 16 | 17 | ## Run with docker-compose 18 | 19 | ### Configuration (all versions) 20 | 21 | First, download a copy of Monica example configuration file: 22 | 23 | ```sh 24 | curl -sS https://raw.githubusercontent.com/monicahq/monica/4.x/.env.example -o .env 25 | ``` 26 | 27 | Open the file in an editor and update it for your own needs: 28 | 29 | - Set `APP_KEY` to a random 32-character string. You can for instance copy and paste the output of `echo -n 'base64:'; openssl rand -base64 32`. 30 | - Edit the `MAIL_*` settings to point to your own [mailserver](https://github.com/monicahq/monica/blob/4.x/docs/installation/mail.md). 31 | - Set `DB_*` settings to point to your database configuration. If you don't want to set a db prefix, be careful to set `DB_PREFIX=` and not `DB_PREFIX=''` as docker will not expand this as an empty string. 32 | - Set `DB_HOST=db` or any name of the database container you will link to. 33 | 34 | 35 | ### With supervisor 36 | 37 | The [`supervisor`](supervisor) examples shows you how to run monica with 38 | - a db container (mariadb:11) 39 | - an app container, which run `supervisord` to handle a web server/fpm, a cron, and a queue. 40 | 41 | This let you use `QUEUE_CONNECTION=database` in your `.env` file. 42 | 43 | 44 | ### With nginx proxy and a self-signed certificate 45 | 46 | [`nginx-proxy-self-signed-ssl`](nginx-proxy-self-signed-ssl) example shows you how to run monica with a self signed ssl certificate, to run the application in `https` mode. 47 | 48 | Set `VIRTUAL_HOST` and `SSL_SUBJECT` with the right domain name, and update `SSL_KEY`, `SSL_CSR`, and `SSL_CERT` accordingly. 49 | This example generates a new self-signed certificate. 50 | 51 | Your browser might warn you about security issue, as a self-signed certificate is not trusted in production mode. For a real domain certificate, see the next section. 52 | 53 | 54 | ### With nginx proxy and a Let's Encrypt certificate 55 | 56 | [`nginx-proxy`](nginx-proxy) example shows you how to run monica and generate a [Let's Encrypt](https://letsencrypt.org/) certificate for your domain. 57 | 58 | Don't forget to set: 59 | - `VIRTUAL_HOST` and `LETSENCRYPT_HOST` with your domain 60 | - `LETSENCRYPT_EMAIL` with a valid email 61 | - `APP_URL` in your `.env` file with the right domain url 62 | 63 | You may want to set `APP_ENV=production` to force the use of `https` scheme. 64 | 65 | This example add a `redis` container, that can be used too, adding these variables to your `.env` file: 66 | - `REDIS_HOST=redis`: mandatory, where `redis` is the name of the redis container 67 | - `CACHE_DRIVER=redis`: to use redis as a cache table 68 | - `QUEUE_CONNECTION=redis`: to use redis as a queue table 69 | -------------------------------------------------------------------------------- /.examples/simple/apache/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with apache backend 2 | 3 | version: "3.9" 4 | 5 | services: 6 | app: 7 | image: monica:apache 8 | depends_on: 9 | - db 10 | ports: 11 | - 80:80 12 | environment: 13 | - APP_ENV=production 14 | - DB_HOST=db 15 | - DB_DATABASE=monica 16 | - DB_USERNAME=monica 17 | - DB_PASSWORD=secret 18 | - LOG_CHANNEL=stderr 19 | - CACHE_DRIVER=database 20 | - SESSION_DRIVER=database 21 | - QUEUE_DRIVER=sync 22 | volumes: 23 | - data:/var/www/html/storage 24 | restart: always 25 | 26 | db: 27 | image: mariadb:11 28 | environment: 29 | - MYSQL_RANDOM_ROOT_PASSWORD=true 30 | - MYSQL_DATABASE=monica 31 | - MYSQL_USER=monica 32 | - MYSQL_PASSWORD=secret 33 | volumes: 34 | - mysqldata:/var/lib/mysql 35 | restart: always 36 | 37 | 38 | volumes: 39 | data: 40 | driver: local 41 | mysqldata: 42 | driver: local 43 | -------------------------------------------------------------------------------- /.examples/simple/fpm/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with fpm+nginx backend 2 | 3 | version: "3.9" 4 | 5 | services: 6 | app: 7 | image: monica:fpm 8 | depends_on: 9 | - db 10 | environment: 11 | - APP_ENV=production 12 | - DB_HOST=db 13 | - DB_DATABASE=monica 14 | - DB_USERNAME=monica 15 | - DB_PASSWORD=secret 16 | - LOG_CHANNEL=stderr 17 | - CACHE_DRIVER=database 18 | - SESSION_DRIVER=database 19 | - QUEUE_DRIVER=sync 20 | volumes: 21 | - data:/var/www/html/storage 22 | restart: always 23 | 24 | web: 25 | build: ./web 26 | ports: 27 | - 80:80 28 | depends_on: 29 | - app 30 | volumes: 31 | - data:/var/www/html/storage:ro 32 | restart: always 33 | 34 | db: 35 | image: mariadb:11 36 | environment: 37 | - MYSQL_RANDOM_ROOT_PASSWORD=true 38 | - MYSQL_DATABASE=monica 39 | - MYSQL_USER=monica 40 | - MYSQL_PASSWORD=secret 41 | volumes: 42 | - mysql:/var/lib/mysql 43 | restart: always 44 | 45 | 46 | volumes: 47 | data: 48 | driver: local 49 | mysql: 50 | driver: local 51 | -------------------------------------------------------------------------------- /.examples/simple/fpm/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm AS monica 2 | 3 | FROM nginx:alpine 4 | 5 | COPY nginx.conf /etc/nginx/nginx.conf 6 | 7 | # Copy content of monica image 8 | COPY --from=monica /var/www/html /var/www/html 9 | RUN ln -sf /var/www/html/storage/app/public /var/www/html/public/storage 10 | -------------------------------------------------------------------------------- /.examples/simple/fpm/web/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log /var/log/nginx/error.log warn; 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | include /etc/nginx/mime.types; 12 | default_type application/octet-stream; 13 | 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | #tcp_nopush on; 22 | 23 | keepalive_timeout 65; 24 | 25 | set_real_ip_from 10.0.0.0/8; 26 | set_real_ip_from 172.16.0.0/12; 27 | set_real_ip_from 192.168.0.0/16; 28 | real_ip_header X-Real-IP; 29 | 30 | # Connect to app service 31 | upstream php-handler { 32 | server app:9000; 33 | } 34 | 35 | server { 36 | listen 80; 37 | 38 | server_name monica; 39 | 40 | ## HSTS ## 41 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 42 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 43 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 44 | # removed from this list could take several months. 45 | # 46 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 47 | 48 | add_header Referrer-Policy "no-referrer" always; 49 | add_header X-Content-Type-Options "nosniff" always; 50 | add_header X-Download-Options "noopen" always; 51 | add_header X-Frame-Options "SAMEORIGIN" always; 52 | add_header X-Permitted-Cross-Domain-Policies "none" always; 53 | add_header X-Robots-Tag "none" always; 54 | add_header X-XSS-Protection "1; mode=block" always; 55 | 56 | # Remove X-Powered-By, which is an information leak 57 | fastcgi_hide_header X-Powered-By; 58 | 59 | root /var/www/html/public; 60 | 61 | index index.html index.htm index.php; 62 | 63 | charset utf-8; 64 | 65 | location / { 66 | try_files $uri $uri/ /index.php?$query_string; 67 | } 68 | 69 | location ~ ^/(?:robots.txt|security.txt) { 70 | allow all; 71 | log_not_found off; 72 | access_log off; 73 | } 74 | 75 | error_page 404 500 502 503 504 /index.php; 76 | 77 | location ~ /\.well-known/(?:carddav|caldav) { 78 | return 301 $scheme://$host/dav; 79 | } 80 | location = /.well-known/security.txt { 81 | return 301 $scheme://$host/security.txt; 82 | } 83 | location ~ /\.(?!well-known).* { 84 | deny all; 85 | } 86 | 87 | # set max upload size 88 | client_max_body_size 10G; 89 | fastcgi_buffers 64 4K; 90 | 91 | # Enable gzip but do not remove ETag headers 92 | gzip on; 93 | gzip_vary on; 94 | gzip_comp_level 4; 95 | gzip_min_length 256; 96 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; 97 | gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; 98 | 99 | # Uncomment if your server is build with the ngx_pagespeed module 100 | # This module is currently not supported. 101 | #pagespeed off; 102 | 103 | location ~ \.php(/|$) { 104 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 105 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 106 | 107 | # Check that the PHP script exists before passing it 108 | try_files $fastcgi_script_name =404; 109 | 110 | fastcgi_pass php-handler; 111 | fastcgi_index index.php; 112 | 113 | include fastcgi_params; 114 | 115 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 116 | # Bypass the fact that try_files resets $fastcgi_path_info 117 | # see: http://trac.nginx.org/nginx/ticket/321 118 | set $path_info $fastcgi_path_info; 119 | fastcgi_param PATH_INFO $path_info; 120 | } 121 | 122 | # Adding the cache control header for js and css files 123 | # Make sure it is BELOW the PHP block 124 | location ~ \.(?:css|js|woff2?|svg|gif|json)$ { 125 | try_files $uri /index.php$request_uri; 126 | add_header Cache-Control "public, max-age=15778463"; 127 | 128 | ## HSTS ## 129 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 130 | # Note it is intended to have those duplicated to the ones above. 131 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 132 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 133 | # removed from this list could take several months. 134 | # 135 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 136 | 137 | add_header Referrer-Policy "no-referrer" always; 138 | add_header X-Content-Type-Options "nosniff" always; 139 | add_header X-Download-Options "noopen" always; 140 | add_header X-Frame-Options "SAMEORIGIN" always; 141 | add_header X-Permitted-Cross-Domain-Policies "none" always; 142 | add_header X-Robots-Tag "none" always; 143 | add_header X-XSS-Protection "1; mode=block" always; 144 | 145 | # Optional: Don't log access to assets 146 | access_log off; 147 | } 148 | 149 | location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ { 150 | try_files $uri /index.php$request_uri; 151 | 152 | # Optional: Don't log access to assets 153 | access_log off; 154 | } 155 | 156 | # deny access to .htaccess files 157 | location ~ /\.ht { 158 | deny all; 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /.examples/supervisor/apache/.env: -------------------------------------------------------------------------------- 1 | APP_ENV=production 2 | APP_DEBUG=false 3 | 4 | # The encryption key. Must be 32 characters long exactly. 5 | # Use `echo -n 'base64:'; openssl rand -base64 32` to generate a random key. 6 | # APP_KEY= 7 | 8 | # The URL of your application. 9 | APP_URL=http://localhost 10 | 11 | # Set trusted proxy IP addresses. 12 | # To trust all proxies that connect directly to your server, use a "*". 13 | APP_TRUSTED_PROXIES= 14 | 15 | # Database information 16 | DB_CONNECTION=mysql 17 | DB_HOST=db 18 | DB_DATABASE=monica 19 | DB_USERNAME=monica 20 | DB_PASSWORD=secret 21 | 22 | # Mail credentials used to send emails from the application. 23 | MAIL_DRIVER=smtp 24 | MAIL_HOST=smtp.domain.com 25 | MAIL_PORT=587 26 | MAIL_USERNAME=username 27 | MAIL_PASSWORD=password 28 | MAIL_ENCRYPTION=tls 29 | # Outgoing emails will be sent with these identity 30 | MAIL_FROM_ADDRESS=email@example.com 31 | MAIL_FROM_NAME="Monica instance" 32 | 33 | LOG_CHANNEL=stderr 34 | 35 | CACHE_DRIVER=database 36 | SESSION_DRIVER=database 37 | QUEUE_DRIVER=sync 38 | -------------------------------------------------------------------------------- /.examples/supervisor/apache/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:apache 2 | 3 | # Use the default production configuration 4 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 5 | 6 | # supervisord dependencies 7 | RUN set -ex; \ 8 | \ 9 | apt-get update; \ 10 | apt-get install -y --no-install-recommends \ 11 | supervisor \ 12 | ; \ 13 | rm -rf /var/lib/apt/lists/* 14 | 15 | COPY supervisord.conf /etc/supervisord.conf 16 | 17 | CMD ["supervisord", "-c", "/etc/supervisord.conf"] 18 | -------------------------------------------------------------------------------- /.examples/supervisor/apache/app/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | user=root 4 | 5 | [program:cron] 6 | command=cron.sh 7 | autostart=true 8 | autorestart=true 9 | 10 | [program:queue] 11 | process_name=%(program_name)s_%(process_num)02d 12 | command=queue.sh 13 | numprocs=1 14 | stdout_logfile=/proc/1/fd/1 15 | stdout_logfile_maxbytes=0 16 | stderr_logfile=/proc/1/fd/2 17 | stderr_logfile_maxbytes=0 18 | autostart=true 19 | autorestart=true 20 | startretries=0 21 | 22 | [program:httpd] 23 | process_name=%(program_name)s_%(process_num)02d 24 | command=entrypoint.sh apache2-foreground 25 | stdout_logfile=/proc/1/fd/1 26 | stdout_logfile_maxbytes=0 27 | stderr_logfile=/proc/1/fd/2 28 | stderr_logfile_maxbytes=0 29 | autostart=true 30 | autorestart=true 31 | -------------------------------------------------------------------------------- /.examples/supervisor/apache/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with a supervisor process 2 | # 3 | # You might want to set these variables in you .env file: 4 | # 5 | #- APP_ENV=production 6 | #- APP_URL with your domain (https scheme) 7 | #- APP_KEY with a random string 8 | # 9 | #- DB_HOST=db 10 | # See `db` container for these values: 11 | #- DB_DATABASE=monica 12 | #- DB_USERNAME=monica 13 | #- DB_PASSWORD=secret 14 | # 15 | 16 | version: "3.9" 17 | 18 | services: 19 | app: 20 | build: ./app 21 | image: monica-app 22 | depends_on: 23 | - db 24 | env_file: .env 25 | ports: 26 | - 80:80 27 | volumes: 28 | - data:/var/www/html/storage 29 | restart: always 30 | 31 | db: 32 | image: mariadb:11 33 | environment: 34 | - MYSQL_RANDOM_ROOT_PASSWORD=true 35 | - MYSQL_DATABASE=monica 36 | - MYSQL_USER=monica 37 | - MYSQL_PASSWORD=secret 38 | volumes: 39 | - mysqldata:/var/lib/mysql 40 | restart: always 41 | 42 | 43 | volumes: 44 | data: 45 | driver: local 46 | mysqldata: 47 | driver: local 48 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm-alpine/.env: -------------------------------------------------------------------------------- 1 | APP_ENV=production 2 | APP_DEBUG=false 3 | 4 | # The encryption key. Must be 32 characters long exactly. 5 | # Use `echo -n 'base64:'; openssl rand -base64 32` to generate a random key. 6 | # APP_KEY= 7 | 8 | # The URL of your application. 9 | APP_URL=http://localhost 10 | 11 | # Set trusted proxy IP addresses. 12 | # To trust all proxies that connect directly to your server, use a "*". 13 | APP_TRUSTED_PROXIES= 14 | 15 | # Database information 16 | DB_CONNECTION=mysql 17 | DB_HOST=db 18 | DB_DATABASE=monica 19 | DB_USERNAME=monica 20 | DB_PASSWORD=secret 21 | 22 | # Mail credentials used to send emails from the application. 23 | MAIL_DRIVER=smtp 24 | MAIL_HOST=smtp.domain.com 25 | MAIL_PORT=587 26 | MAIL_USERNAME=username 27 | MAIL_PASSWORD=password 28 | MAIL_ENCRYPTION=tls 29 | # Outgoing emails will be sent with these identity 30 | MAIL_FROM_ADDRESS=email@example.com 31 | MAIL_FROM_NAME="Monica instance" 32 | 33 | LOG_CHANNEL=stderr 34 | 35 | CACHE_DRIVER=database 36 | SESSION_DRIVER=database 37 | QUEUE_DRIVER=sync 38 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm-alpine/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm-alpine 2 | 3 | # Use the default production configuration 4 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 5 | 6 | # supervisord dependencies 7 | RUN set -ex; \ 8 | \ 9 | apk add --no-cache \ 10 | supervisor \ 11 | ; 12 | 13 | COPY supervisord.conf /etc/supervisord.conf 14 | 15 | CMD ["supervisord", "-c", "/etc/supervisord.conf"] 16 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm-alpine/app/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | user=root 4 | 5 | [program:cron] 6 | command=cron.sh 7 | autostart=true 8 | autorestart=true 9 | 10 | [program:queue] 11 | process_name=%(program_name)s_%(process_num)02d 12 | command=queue.sh 13 | numprocs=1 14 | stdout_logfile=/proc/1/fd/1 15 | stdout_logfile_maxbytes=0 16 | stderr_logfile=/proc/1/fd/2 17 | stderr_logfile_maxbytes=0 18 | autostart=true 19 | autorestart=true 20 | startretries=0 21 | 22 | [program:fpm] 23 | process_name=%(program_name)s_%(process_num)02d 24 | command=entrypoint.sh php-fpm 25 | stdout_logfile=/proc/1/fd/1 26 | stdout_logfile_maxbytes=0 27 | stderr_logfile=/proc/1/fd/2 28 | stderr_logfile_maxbytes=0 29 | autostart=true 30 | autorestart=true 31 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm-alpine/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with a supervisor process 2 | # 3 | # You might want to set these variables in you .env file: 4 | # 5 | #- APP_ENV=production 6 | #- APP_URL with your domain (https scheme) 7 | #- APP_KEY with a random string 8 | # 9 | #- DB_HOST=db 10 | # See `db` container for these values: 11 | #- DB_DATABASE=monica 12 | #- DB_USERNAME=monica 13 | #- DB_PASSWORD=secret 14 | # 15 | 16 | version: "3.9" 17 | 18 | services: 19 | app: 20 | build: ./app 21 | depends_on: 22 | - db 23 | env_file: .env 24 | volumes: 25 | - data:/var/www/html/storage 26 | restart: always 27 | 28 | web: 29 | build: ./web 30 | restart: always 31 | ports: 32 | - 80:80 33 | volumes: 34 | - data:/var/www/html/storage:ro 35 | depends_on: 36 | - app 37 | 38 | db: 39 | image: mariadb:11 40 | environment: 41 | - MYSQL_RANDOM_ROOT_PASSWORD=true 42 | - MYSQL_DATABASE=monica 43 | - MYSQL_USER=monica 44 | - MYSQL_PASSWORD=secret 45 | volumes: 46 | - mysqldata:/var/lib/mysql 47 | restart: always 48 | 49 | 50 | volumes: 51 | data: 52 | driver: local 53 | mysql: 54 | driver: local 55 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm-alpine/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm-alpine AS monica 2 | 3 | FROM nginx:alpine 4 | 5 | COPY nginx.conf /etc/nginx/nginx.conf 6 | 7 | # Copy content of monica image 8 | COPY --from=monica /var/www/html /var/www/html 9 | RUN ln -sf /var/www/html/storage/app/public /var/www/html/public/storage 10 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm-alpine/web/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log /var/log/nginx/error.log warn; 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | include /etc/nginx/mime.types; 12 | default_type application/octet-stream; 13 | 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | #tcp_nopush on; 22 | 23 | keepalive_timeout 65; 24 | 25 | set_real_ip_from 10.0.0.0/8; 26 | set_real_ip_from 172.16.0.0/12; 27 | set_real_ip_from 192.168.0.0/16; 28 | real_ip_header X-Real-IP; 29 | 30 | # Connect to app service 31 | upstream php-handler { 32 | server app:9000; 33 | } 34 | 35 | server { 36 | listen 80; 37 | 38 | server_name monica; 39 | 40 | ## HSTS ## 41 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 42 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 43 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 44 | # removed from this list could take several months. 45 | # 46 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 47 | 48 | add_header Referrer-Policy "no-referrer" always; 49 | add_header X-Content-Type-Options "nosniff" always; 50 | add_header X-Download-Options "noopen" always; 51 | add_header X-Frame-Options "SAMEORIGIN" always; 52 | add_header X-Permitted-Cross-Domain-Policies "none" always; 53 | add_header X-Robots-Tag "none" always; 54 | add_header X-XSS-Protection "1; mode=block" always; 55 | 56 | # Remove X-Powered-By, which is an information leak 57 | fastcgi_hide_header X-Powered-By; 58 | 59 | root /var/www/html/public; 60 | 61 | index index.html index.htm index.php; 62 | 63 | charset utf-8; 64 | 65 | location / { 66 | try_files $uri $uri/ /index.php?$query_string; 67 | } 68 | 69 | location ~ ^/(?:robots.txt|security.txt) { 70 | allow all; 71 | log_not_found off; 72 | access_log off; 73 | } 74 | 75 | error_page 404 500 502 503 504 /index.php; 76 | 77 | location ~ /\.well-known/(?:carddav|caldav) { 78 | return 301 $scheme://$host/dav; 79 | } 80 | location = /.well-known/security.txt { 81 | return 301 $scheme://$host/security.txt; 82 | } 83 | location ~ /\.(?!well-known).* { 84 | deny all; 85 | } 86 | 87 | # set max upload size 88 | client_max_body_size 10G; 89 | fastcgi_buffers 64 4K; 90 | 91 | # Enable gzip but do not remove ETag headers 92 | gzip on; 93 | gzip_vary on; 94 | gzip_comp_level 4; 95 | gzip_min_length 256; 96 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; 97 | gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; 98 | 99 | # Uncomment if your server is build with the ngx_pagespeed module 100 | # This module is currently not supported. 101 | #pagespeed off; 102 | 103 | location ~ \.php(/|$) { 104 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 105 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 106 | 107 | # Check that the PHP script exists before passing it 108 | try_files $fastcgi_script_name =404; 109 | 110 | fastcgi_pass php-handler; 111 | fastcgi_index index.php; 112 | 113 | include fastcgi_params; 114 | 115 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 116 | # Bypass the fact that try_files resets $fastcgi_path_info 117 | # see: http://trac.nginx.org/nginx/ticket/321 118 | set $path_info $fastcgi_path_info; 119 | fastcgi_param PATH_INFO $path_info; 120 | } 121 | 122 | # Adding the cache control header for js and css files 123 | # Make sure it is BELOW the PHP block 124 | location ~ \.(?:css|js|woff2?|svg|gif|json)$ { 125 | try_files $uri /index.php$request_uri; 126 | add_header Cache-Control "public, max-age=15778463"; 127 | 128 | ## HSTS ## 129 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 130 | # Note it is intended to have those duplicated to the ones above. 131 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 132 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 133 | # removed from this list could take several months. 134 | # 135 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 136 | 137 | add_header Referrer-Policy "no-referrer" always; 138 | add_header X-Content-Type-Options "nosniff" always; 139 | add_header X-Download-Options "noopen" always; 140 | add_header X-Frame-Options "SAMEORIGIN" always; 141 | add_header X-Permitted-Cross-Domain-Policies "none" always; 142 | add_header X-Robots-Tag "none" always; 143 | add_header X-XSS-Protection "1; mode=block" always; 144 | 145 | # Optional: Don't log access to assets 146 | access_log off; 147 | } 148 | 149 | location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ { 150 | try_files $uri /index.php$request_uri; 151 | 152 | # Optional: Don't log access to assets 153 | access_log off; 154 | } 155 | 156 | # deny access to .htaccess files 157 | location ~ /\.ht { 158 | deny all; 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm/.env: -------------------------------------------------------------------------------- 1 | APP_ENV=production 2 | APP_DEBUG=false 3 | 4 | # The encryption key. Must be 32 characters long exactly. 5 | # Use `echo -n 'base64:'; openssl rand -base64 32` to generate a random key. 6 | # APP_KEY= 7 | 8 | # The URL of your application. 9 | APP_URL=http://localhost 10 | 11 | # Set trusted proxy IP addresses. 12 | # To trust all proxies that connect directly to your server, use a "*". 13 | APP_TRUSTED_PROXIES= 14 | 15 | # Database information 16 | DB_CONNECTION=mysql 17 | DB_HOST=db 18 | DB_DATABASE=monica 19 | DB_USERNAME=monica 20 | DB_PASSWORD=secret 21 | 22 | # Mail credentials used to send emails from the application. 23 | MAIL_DRIVER=smtp 24 | MAIL_HOST=smtp.domain.com 25 | MAIL_PORT=587 26 | MAIL_USERNAME=username 27 | MAIL_PASSWORD=password 28 | MAIL_ENCRYPTION=tls 29 | # Outgoing emails will be sent with these identity 30 | MAIL_FROM_ADDRESS=email@example.com 31 | MAIL_FROM_NAME="Monica instance" 32 | 33 | LOG_CHANNEL=stderr 34 | 35 | CACHE_DRIVER=database 36 | SESSION_DRIVER=database 37 | QUEUE_DRIVER=sync 38 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm 2 | 3 | # Use the default production configuration 4 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 5 | 6 | # supervisord dependencies 7 | RUN set -ex; \ 8 | \ 9 | apt-get update; \ 10 | apt-get install -y --no-install-recommends \ 11 | supervisor \ 12 | ; \ 13 | rm -rf /var/lib/apt/lists/* 14 | 15 | COPY supervisord.conf /etc/supervisord.conf 16 | 17 | CMD ["supervisord", "-c", "/etc/supervisord.conf"] 18 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm/app/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | user=root 4 | 5 | [program:cron] 6 | command=cron.sh 7 | autostart=true 8 | autorestart=true 9 | 10 | [program:queue] 11 | process_name=%(program_name)s_%(process_num)02d 12 | command=queue.sh 13 | numprocs=1 14 | stdout_logfile=/proc/1/fd/1 15 | stdout_logfile_maxbytes=0 16 | stderr_logfile=/proc/1/fd/2 17 | stderr_logfile_maxbytes=0 18 | autostart=true 19 | autorestart=true 20 | startretries=0 21 | 22 | [program:fpm] 23 | process_name=%(program_name)s_%(process_num)02d 24 | command=entrypoint.sh php-fpm 25 | stdout_logfile=/proc/1/fd/1 26 | stdout_logfile_maxbytes=0 27 | stderr_logfile=/proc/1/fd/2 28 | stderr_logfile_maxbytes=0 29 | autostart=true 30 | autorestart=true 31 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Run Monica with a supervisor process 2 | # 3 | # You might want to set these variables in you .env file: 4 | # 5 | #- APP_ENV=production 6 | #- APP_URL with your domain (https scheme) 7 | #- APP_KEY with a random string 8 | # 9 | #- DB_HOST=db 10 | # See `db` container for these values: 11 | #- DB_DATABASE=monica 12 | #- DB_USERNAME=monica 13 | #- DB_PASSWORD=secret 14 | # 15 | 16 | version: "3.9" 17 | 18 | services: 19 | app: 20 | build: ./app 21 | image: monica-app 22 | depends_on: 23 | - db 24 | env_file: .env 25 | volumes: 26 | - data:/var/www/html/storage 27 | restart: always 28 | 29 | web: 30 | build: ./web 31 | image: monica-web 32 | restart: always 33 | ports: 34 | - 80:80 35 | volumes: 36 | - data:/var/www/html/storage:ro 37 | depends_on: 38 | - app 39 | 40 | db: 41 | image: mariadb:11 42 | environment: 43 | - MYSQL_RANDOM_ROOT_PASSWORD=true 44 | - MYSQL_DATABASE=monica 45 | - MYSQL_USER=monica 46 | - MYSQL_PASSWORD=secret 47 | volumes: 48 | - mysqldata:/var/lib/mysql 49 | restart: always 50 | 51 | 52 | volumes: 53 | data: 54 | driver: local 55 | mysql: 56 | driver: local 57 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM monica:fpm AS monica 2 | 3 | FROM nginx:alpine 4 | 5 | COPY nginx.conf /etc/nginx/nginx.conf 6 | 7 | # Copy content of monica image 8 | COPY --from=monica /var/www/html /var/www/html 9 | RUN ln -sf /var/www/html/storage/app/public /var/www/html/public/storage 10 | -------------------------------------------------------------------------------- /.examples/supervisor/fpm/web/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log /var/log/nginx/error.log warn; 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | include /etc/nginx/mime.types; 12 | default_type application/octet-stream; 13 | 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | #tcp_nopush on; 22 | 23 | keepalive_timeout 65; 24 | 25 | set_real_ip_from 10.0.0.0/8; 26 | set_real_ip_from 172.16.0.0/12; 27 | set_real_ip_from 192.168.0.0/16; 28 | real_ip_header X-Real-IP; 29 | 30 | # Connect to app service 31 | upstream php-handler { 32 | server app:9000; 33 | } 34 | 35 | server { 36 | listen 80; 37 | 38 | server_name monica; 39 | 40 | ## HSTS ## 41 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 42 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 43 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 44 | # removed from this list could take several months. 45 | # 46 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 47 | 48 | add_header Referrer-Policy "no-referrer" always; 49 | add_header X-Content-Type-Options "nosniff" always; 50 | add_header X-Download-Options "noopen" always; 51 | add_header X-Frame-Options "SAMEORIGIN" always; 52 | add_header X-Permitted-Cross-Domain-Policies "none" always; 53 | add_header X-Robots-Tag "none" always; 54 | add_header X-XSS-Protection "1; mode=block" always; 55 | 56 | # Remove X-Powered-By, which is an information leak 57 | fastcgi_hide_header X-Powered-By; 58 | 59 | root /var/www/html/public; 60 | 61 | index index.html index.htm index.php; 62 | 63 | charset utf-8; 64 | 65 | location / { 66 | try_files $uri $uri/ /index.php?$query_string; 67 | } 68 | 69 | location ~ ^/(?:robots.txt|security.txt) { 70 | allow all; 71 | log_not_found off; 72 | access_log off; 73 | } 74 | 75 | error_page 404 500 502 503 504 /index.php; 76 | 77 | location ~ /\.well-known/(?:carddav|caldav) { 78 | return 301 $scheme://$host/dav; 79 | } 80 | location = /.well-known/security.txt { 81 | return 301 $scheme://$host/security.txt; 82 | } 83 | location ~ /\.(?!well-known).* { 84 | deny all; 85 | } 86 | 87 | # set max upload size 88 | client_max_body_size 10G; 89 | fastcgi_buffers 64 4K; 90 | 91 | # Enable gzip but do not remove ETag headers 92 | gzip on; 93 | gzip_vary on; 94 | gzip_comp_level 4; 95 | gzip_min_length 256; 96 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; 97 | gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; 98 | 99 | # Uncomment if your server is build with the ngx_pagespeed module 100 | # This module is currently not supported. 101 | #pagespeed off; 102 | 103 | location ~ \.php(/|$) { 104 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 105 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 106 | 107 | # Check that the PHP script exists before passing it 108 | try_files $fastcgi_script_name =404; 109 | 110 | fastcgi_pass php-handler; 111 | fastcgi_index index.php; 112 | 113 | include fastcgi_params; 114 | 115 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 116 | # Bypass the fact that try_files resets $fastcgi_path_info 117 | # see: http://trac.nginx.org/nginx/ticket/321 118 | set $path_info $fastcgi_path_info; 119 | fastcgi_param PATH_INFO $path_info; 120 | } 121 | 122 | # Adding the cache control header for js and css files 123 | # Make sure it is BELOW the PHP block 124 | location ~ \.(?:css|js|woff2?|svg|gif|json)$ { 125 | try_files $uri /index.php$request_uri; 126 | add_header Cache-Control "public, max-age=15778463"; 127 | 128 | ## HSTS ## 129 | # Add the 'Strict-Transport-Security' headers to enable HSTS protocol. 130 | # Note it is intended to have those duplicated to the ones above. 131 | # WARNING: Only add the preload option once you read about the consequences: https://hstspreload.org/. 132 | # This form will add the domain to a hardcoded list that is shipped in all major browsers and getting 133 | # removed from this list could take several months. 134 | # 135 | #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" always; 136 | 137 | add_header Referrer-Policy "no-referrer" always; 138 | add_header X-Content-Type-Options "nosniff" always; 139 | add_header X-Download-Options "noopen" always; 140 | add_header X-Frame-Options "SAMEORIGIN" always; 141 | add_header X-Permitted-Cross-Domain-Policies "none" always; 142 | add_header X-Robots-Tag "none" always; 143 | add_header X-XSS-Protection "1; mode=block" always; 144 | 145 | # Optional: Don't log access to assets 146 | access_log off; 147 | } 148 | 149 | location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ { 150 | try_files $uri /index.php$request_uri; 151 | 152 | # Optional: Don't log access to assets 153 | access_log off; 154 | } 155 | 156 | # deny access to .htaccess files 157 | location ~ /\.ht { 158 | deny all; 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | README.md export-ignore 3 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Monica's docker 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | release: 9 | types: [created] 10 | 11 | 12 | env: 13 | bashbrew-version: 0.1.12 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | name: Build ${{ matrix.release }}-${{ matrix.variant }} (${{ matrix.arch }}) 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | variant: [apache, fpm, fpm-alpine] 23 | arch: [amd64, i386] 24 | release: [4, 5] 25 | include: 26 | - release: 4 27 | php-version: 8.2 28 | - release: 5 29 | php-version: 8.3 30 | 31 | steps: 32 | - uses: actions/checkout@v4 33 | - uses: actions/checkout@v4 34 | with: 35 | # repository: docker-library/official-images 36 | repository: asbiin/official-images 37 | path: official-images 38 | ref: monica-tests 39 | 40 | - name: Fix image 41 | if: matrix.arch == 'i386' 42 | run: | 43 | sed -i -e 's/FROM php/FROM i386\/php/g' "${{ matrix.release }}/${{ matrix.variant }}/Dockerfile" 44 | 45 | - name: Update base image 46 | run: | 47 | docker pull ${{ env.prefix }}php:${{ matrix.php-version }}-${{ matrix.variant }} 48 | env: 49 | prefix: ${{ (matrix.arch == 'i386') && 'i386/' || '' }} 50 | 51 | - name: Build image ${{ matrix.release }}-${{ matrix.variant }} ${{ matrix.arch }} 52 | run: | 53 | docker build ${{ matrix.release }}/${{ matrix.variant }} -t monica:${{ matrix.release }}-${{ matrix.variant }} 54 | docker images 55 | 56 | - name: Test image ${{ matrix.release }}-${{ matrix.variant }} ${{ matrix.arch }} 57 | if: matrix.arch != 'i386' || matrix.variant != 'apache' 58 | run: | 59 | official-images/test/run.sh monica:${{ matrix.release }}-${{ matrix.variant }} 60 | 61 | - name: Publish package 62 | if: github.ref == 'refs/heads/main' && matrix.arch != 'i386' 63 | run: | 64 | echo "$password" | docker login ghcr.io -u $username --password-stdin 65 | docker tag monica:${{ matrix.release }}-${{ matrix.variant }} ghcr.io/monicahq/monica-dev:${{ matrix.release }}-${{ matrix.variant }} 66 | docker push ghcr.io/monicahq/monica-dev:${{ matrix.release }}-${{ matrix.variant }} 67 | env: 68 | username: ${{ secrets.CR_USER }} 69 | password: ${{ secrets.CR_PAT }} 70 | 71 | test: 72 | runs-on: ubuntu-latest 73 | steps: 74 | - uses: actions/checkout@v4 75 | - name: Test update script 76 | run: | 77 | hash_before=$(git write-tree) 78 | ./update.sh 79 | bash -c "[[ $hash_before = $(git add -A && git write-tree) ]]" 80 | 81 | - name: Install bashbrew 82 | run: | 83 | curl -fsSL -o bashbrew https://github.com/docker-library/bashbrew/releases/download/v${{ env.bashbrew-version }}/bashbrew-amd64 84 | chmod +x "bashbrew" 85 | - name: Run stackbrew 86 | run: | 87 | ./generate-stackbrew-library.sh 88 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish official image 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | bashbrew-version: 0.1.12 8 | 9 | 10 | jobs: 11 | release: 12 | runs-on: ubuntu-latest 13 | 14 | environment: docker-official 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | path: monica-docker 20 | persist-credentials: false 21 | - uses: actions/checkout@v4 22 | with: 23 | repository: docker-library/official-images 24 | fetch-depth: 0 25 | path: official-images 26 | persist-credentials: false 27 | 28 | - name: Install bashbrew 29 | working-directory: monica-docker 30 | run: | 31 | curl -fsSL -o bashbrew https://github.com/docker-library/bashbrew/releases/download/v${{ env.bashbrew-version }}/bashbrew-amd64 32 | chmod +x "bashbrew" 33 | 34 | - name: Run stackbrew 35 | working-directory: monica-docker 36 | run: | 37 | ./generate-stackbrew-library.sh | tee ../official-images/library/monica 38 | 39 | - name: Update 40 | working-directory: official-images 41 | run: | 42 | remote=upstream 43 | remoteurl="https://$USER_NAME:$GH_TOKEN@github.com/$USER_NAME/official-images.git" 44 | latest="$(curl -fsSL 'https://api.github.com/repos/monicahq/monica/releases/latest' | jq -r '.tag_name' | cut -c 2-)" 45 | branch="monica-v$latest" 46 | message="Update Monica to v$latest" 47 | 48 | status=$(git status --porcelain) 49 | if [ -n "$status" ]; then 50 | git status 51 | git add library/monica 52 | git config user.email $USER_EMAIL 53 | git config user.name $USER_NAME 54 | git checkout -b $branch 55 | git commit -m "$message" 56 | git remote remove $remote || true 57 | git remote add -f $remote "$remoteurl" || true 58 | git push --set-upstream $remote $branch 59 | gh pr create --repo docker-library/official-images --title "$message" --body "Update Monica to [v$latest](https://github.com/monicahq/monica/releases/tag/v$latest)." 60 | else 61 | echo "Already up to date" 62 | fi 63 | env: 64 | USER_EMAIL: ${{ secrets.USER_EMAIL }} 65 | USER_NAME: ${{ secrets.USER_NAME }} 66 | GH_TOKEN: ${{ secrets.PUSH_GITHUB_TOKEN }} 67 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release update 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | release: 8 | runs-on: ubuntu-latest 9 | 10 | environment: monicahq-docker 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | persist-credentials: false 17 | 18 | - name: Run update script 19 | run: | 20 | ./update.sh 21 | 22 | - name: Update 23 | run: | 24 | remote=upstream 25 | remoteurl="https://$USER_NAME:$GH_TOKEN@github.com/monicahq/docker.git" 26 | latest="$(curl -fsSL 'https://api.github.com/repos/monicahq/monica/releases/latest' | jq -r '.tag_name' | cut -c 2-)" 27 | branch="release-v$latest" 28 | message="Update to v$latest" 29 | 30 | status=$(git status --porcelain) 31 | if [ -n "$status" ]; then 32 | git status 33 | git add -A 34 | git config user.email $USER_EMAIL 35 | git config user.name $USER_NAME 36 | git checkout -b $branch 37 | git commit -m "$message" 38 | git remote remove $remote || true 39 | git remote add -f $remote "$remoteurl" || true 40 | git push --set-upstream $remote $branch 41 | gh pr create --title "$message" --body "Update Monica to [v$latest](https://github.com/monicahq/monica/releases/tag/v$latest)." 42 | else 43 | echo "Already up to date" 44 | fi 45 | env: 46 | USER_EMAIL: ${{ secrets.USER_EMAIL }} 47 | USER_NAME: ${{ secrets.USER_NAME }} 48 | GH_TOKEN: ${{ secrets.PUSH_GITHUB_TOKEN }} 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bashbrew 2 | -------------------------------------------------------------------------------- /.templates/Dockerfile-alpine.template: -------------------------------------------------------------------------------- 1 | %%HEAD%% 2 | 3 | # entrypoint.sh dependencies 4 | RUN set -ex; \ 5 | \ 6 | apk add --no-cache \ 7 | bash \ 8 | coreutils 9 | 10 | # Install required PHP extensions 11 | RUN set -ex; \ 12 | \ 13 | apk add --no-cache --virtual .build-deps \ 14 | $PHPIZE_DEPS \ 15 | icu-dev \ 16 | zlib-dev \ 17 | libzip-dev \ 18 | libxml2-dev \ 19 | freetype-dev \ 20 | libpng-dev \ 21 | libpq-dev \ 22 | libjpeg-turbo-dev \ 23 | jpeg-dev \ 24 | gmp-dev \ 25 | libmemcached-dev \ 26 | libwebp-dev \ 27 | ; \ 28 | \ 29 | docker-php-ext-configure intl; \ 30 | docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \ 31 | docker-php-ext-configure gmp; \ 32 | docker-php-ext-install -j "$(nproc)" \ 33 | intl \ 34 | zip \ 35 | bcmath \ 36 | gd \ 37 | gmp \ 38 | pdo_mysql \ 39 | mysqli \ 40 | pdo_pgsql \ 41 | soap \ 42 | ; \ 43 | # pecl will claim success even if one install fails, so we need to perform each install separately 44 | pecl install APCu-%%APCU_VERSION%%; \ 45 | pecl install memcached-%%MEMCACHED_VERSION%%; \ 46 | pecl install redis-%%REDIS_VERSION%%; \ 47 | \ 48 | docker-php-ext-enable \ 49 | apcu \ 50 | memcached \ 51 | redis \ 52 | ; \ 53 | \ 54 | runDeps="$( \ 55 | scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ 56 | | tr ',' '\n' \ 57 | | sort -u \ 58 | | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ 59 | )"; \ 60 | apk add --no-network --virtual .monica-phpext-rundeps $runDeps; \ 61 | apk del --no-network .build-deps 62 | 63 | %%EXTRA_INSTALL%% 64 | 65 | RUN set -ex; \ 66 | apk add --no-cache --virtual .fetch-deps \ 67 | bzip2 \ 68 | gnupg \ 69 | ; \ 70 | \ 71 | %%INSTALL%% \ 72 | \ 73 | apk del .fetch-deps 74 | 75 | %%FOOT%% 76 | -------------------------------------------------------------------------------- /.templates/Dockerfile-apache.template: -------------------------------------------------------------------------------- 1 | RUN set -ex; \ 2 | \ 3 | a2enmod headers rewrite remoteip; \ 4 | { \ 5 | echo RemoteIPHeader X-Real-IP; \ 6 | echo RemoteIPTrustedProxy 10.0.0.0/8; \ 7 | echo RemoteIPTrustedProxy 172.16.0.0/12; \ 8 | echo RemoteIPTrustedProxy 192.168.0.0/16; \ 9 | } > $APACHE_CONFDIR/conf-available/remoteip.conf; \ 10 | a2enconf remoteip 11 | 12 | # set apache config LimitRequestBody 13 | ENV APACHE_BODY_LIMIT 1073741824 14 | RUN set -ex; \ 15 | \ 16 | { \ 17 | echo 'LimitRequestBody ${APACHE_BODY_LIMIT}'; \ 18 | } > $APACHE_CONFDIR/conf-available/apache-limits.conf; \ 19 | a2enconf apache-limits 20 | 21 | RUN set -ex; \ 22 | APACHE_DOCUMENT_ROOT=/var/www/html/public; \ 23 | sed -ri -e "s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g" $APACHE_CONFDIR/sites-available/*.conf; \ 24 | sed -ri -e "s!/var/www/!${APACHE_DOCUMENT_ROOT}!g" $APACHE_CONFDIR/apache2.conf $APACHE_CONFDIR/conf-available/*.conf 25 | -------------------------------------------------------------------------------- /.templates/Dockerfile-debian.template: -------------------------------------------------------------------------------- 1 | %%HEAD%% 2 | 3 | # entrypoint.sh dependencies 4 | RUN set -ex; \ 5 | \ 6 | apt-get update; \ 7 | apt-get install -y --no-install-recommends \ 8 | bash \ 9 | busybox-static \ 10 | ; \ 11 | rm -rf /var/lib/apt/lists/* 12 | 13 | # Install required PHP extensions 14 | RUN set -ex; \ 15 | \ 16 | savedAptMark="$(apt-mark showmanual)"; \ 17 | \ 18 | apt-get update; \ 19 | apt-get install -y --no-install-recommends \ 20 | libicu-dev \ 21 | zlib1g-dev \ 22 | libzip-dev \ 23 | libpng-dev \ 24 | libpq-dev \ 25 | libxml2-dev \ 26 | libfreetype6-dev \ 27 | libjpeg62-turbo-dev \ 28 | libgmp-dev \ 29 | libmemcached-dev \ 30 | libssl-dev \ 31 | libwebp-dev \ 32 | libcurl4-openssl-dev \ 33 | ; \ 34 | \ 35 | debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ 36 | if [ ! -e /usr/include/gmp.h ]; then ln -s /usr/include/$debMultiarch/gmp.h /usr/include/gmp.h; fi;\ 37 | docker-php-ext-configure intl; \ 38 | docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \ 39 | docker-php-ext-configure gmp; \ 40 | docker-php-ext-install -j$(nproc) \ 41 | intl \ 42 | zip \ 43 | bcmath \ 44 | gd \ 45 | gmp \ 46 | pdo_mysql \ 47 | mysqli \ 48 | pdo_pgsql \ 49 | soap \ 50 | ; \ 51 | \ 52 | # pecl will claim success even if one install fails, so we need to perform each install separately 53 | pecl install APCu-%%APCU_VERSION%%; \ 54 | pecl install memcached-%%MEMCACHED_VERSION%%; \ 55 | pecl install redis-%%REDIS_VERSION%%; \ 56 | \ 57 | docker-php-ext-enable \ 58 | apcu \ 59 | memcached \ 60 | redis \ 61 | ; \ 62 | \ 63 | # reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies 64 | apt-mark auto '.*' > /dev/null; \ 65 | apt-mark manual $savedAptMark; \ 66 | ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ 67 | | awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); print so }' \ 68 | | sort -u \ 69 | | xargs -r dpkg-query -S \ 70 | | cut -d: -f1 \ 71 | | sort -u \ 72 | | xargs -rt apt-mark manual; \ 73 | \ 74 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ 75 | rm -rf /var/lib/apt/lists/* 76 | 77 | %%EXTRA_INSTALL%% 78 | 79 | RUN set -ex; \ 80 | fetchDeps=" \ 81 | gnupg \ 82 | dirmngr \ 83 | "; \ 84 | apt-get update; \ 85 | apt-get install -y --no-install-recommends $fetchDeps; \ 86 | \ 87 | %%INSTALL%% \ 88 | \ 89 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ 90 | rm -rf /var/lib/apt/lists/* 91 | 92 | %%FOOT%% 93 | -------------------------------------------------------------------------------- /.templates/Dockerfile-extra.template: -------------------------------------------------------------------------------- 1 | # Set crontab for schedules 2 | RUN set -ex; \ 3 | \ 4 | mkdir -p /var/spool/cron/crontabs; \ 5 | rm -f /var/spool/cron/crontabs/root; \ 6 | echo '* * * * * php /var/www/html/artisan schedule:run -v' > /var/spool/cron/crontabs/www-data 7 | 8 | # Opcache 9 | ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \ 10 | PHP_OPCACHE_MAX_ACCELERATED_FILES="20000" \ 11 | PHP_OPCACHE_MEMORY_CONSUMPTION="192" \ 12 | PHP_OPCACHE_MAX_WASTED_PERCENTAGE="10" 13 | # Limits 14 | ENV PHP_MEMORY_LIMIT="512M" \ 15 | PHP_UPLOAD_LIMIT="512M" 16 | RUN set -ex; \ 17 | \ 18 | docker-php-ext-enable opcache; \ 19 | { \ 20 | echo '[opcache]'; \ 21 | echo 'opcache.enable=1'; \ 22 | echo 'opcache.revalidate_freq=0'; \ 23 | echo 'opcache.validate_timestamps=${PHP_OPCACHE_VALIDATE_TIMESTAMPS}'; \ 24 | echo 'opcache.max_accelerated_files=${PHP_OPCACHE_MAX_ACCELERATED_FILES}'; \ 25 | echo 'opcache.memory_consumption=${PHP_OPCACHE_MEMORY_CONSUMPTION}'; \ 26 | echo 'opcache.max_wasted_percentage=${PHP_OPCACHE_MAX_WASTED_PERCENTAGE}'; \ 27 | echo 'opcache.interned_strings_buffer=16'; \ 28 | echo 'opcache.fast_shutdown=1'; \ 29 | } > $PHP_INI_DIR/conf.d/opcache-recommended.ini; \ 30 | \ 31 | echo 'apc.enable_cli=1' >> $PHP_INI_DIR/conf.d/docker-php-ext-apcu.ini; \ 32 | \ 33 | { \ 34 | echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \ 35 | echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \ 36 | echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \ 37 | } > $PHP_INI_DIR/conf.d/limits.ini; 38 | 39 | %%APACHE_DOCUMENT%% 40 | 41 | WORKDIR /var/www/html 42 | 43 | # Define Monica version 44 | ENV MONICA_VERSION %%VERSION%% 45 | LABEL org.opencontainers.image.revision="%%COMMIT%%" \ 46 | org.opencontainers.image.version="%%VERSION%%" 47 | -------------------------------------------------------------------------------- /.templates/Dockerfile-foot4.template: -------------------------------------------------------------------------------- 1 | COPY entrypoint.sh \ 2 | queue.sh \ 3 | cron.sh \ 4 | /usr/local/bin/ 5 | 6 | ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] 7 | CMD ["%%CMD%%"] 8 | -------------------------------------------------------------------------------- /.templates/Dockerfile-foot5.template: -------------------------------------------------------------------------------- 1 | COPY --chown=www-data:www-data env.production .env 2 | COPY entrypoint.sh \ 3 | queue.sh \ 4 | cron.sh \ 5 | /usr/local/bin/ 6 | 7 | ENTRYPOINT ["entrypoint.sh"] 8 | CMD ["%%CMD%%"] 9 | -------------------------------------------------------------------------------- /.templates/Dockerfile-head.template: -------------------------------------------------------------------------------- 1 | FROM php:%%PHP_VERSION%%-%%VARIANT%% 2 | 3 | # opencontainers annotations https://github.com/opencontainers/image-spec/blob/master/annotations.md 4 | %%LABEL%% 5 | -------------------------------------------------------------------------------- /.templates/Dockerfile-install.template: -------------------------------------------------------------------------------- 1 | for ext in tar.bz2 tar.bz2.asc; do \ 2 | curl -fsSL -o monica-${MONICA_VERSION}.$ext "https://github.com/monicahq/monica/releases/download/${MONICA_VERSION}/monica-${MONICA_VERSION}.$ext"; \ 3 | done; \ 4 | \ 5 | GPGKEY='BDAB0D0D36A00466A2964E85DE15667131EA6018'; \ 6 | export GNUPGHOME="$(mktemp -d)"; \ 7 | gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$GPGKEY"; \ 8 | gpg --batch --verify monica-${MONICA_VERSION}.tar.bz2.asc monica-${MONICA_VERSION}.tar.bz2; \ 9 | \ 10 | tar -xf monica-${MONICA_VERSION}.tar.bz2 -C /var/www/html --strip-components=1; \ 11 | \ 12 | gpgconf --kill all; \ 13 | rm -rf "$GNUPGHOME" monica-${MONICA_VERSION}.tar.bz2 monica-${MONICA_VERSION}.tar.bz2.asc; \ 14 | \ 15 | cp /var/www/html/.env.example /var/www/html/.env; \ 16 | chown -R www-data:www-data /var/www/html; -------------------------------------------------------------------------------- /.templates/Dockerfile-label.template: -------------------------------------------------------------------------------- 1 | LABEL org.opencontainers.image.authors="Alexis Saettler " \ 2 | org.opencontainers.image.title="MonicaHQ, the Personal Relationship Manager" \ 3 | org.opencontainers.image.description="This is MonicaHQ, your personal memory! MonicaHQ is like a CRM but for the friends, family, and acquaintances around you." \ 4 | org.opencontainers.image.url="https://monicahq.com" \ 5 | org.opencontainers.image.source="https://github.com/monicahq/docker" \ 6 | org.opencontainers.image.vendor="Monica" 7 | -------------------------------------------------------------------------------- /.templates/scripts/4/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec busybox crond -f -l 0 -L /proc/1/fd/1 5 | -------------------------------------------------------------------------------- /.templates/scripts/4/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -Eeo pipefail 4 | 5 | # set environment variables with docker secrets in /run/secrets/* 6 | supportedSecrets=( "DB_PASSWORD" 7 | "DATABASE_URL" 8 | "APP_KEY" 9 | "HASH_SALT" 10 | "MAIL_PASSWORD" 11 | "REDIS_PASSWORD" 12 | "AWS_ACCESS_KEY_ID" 13 | "AWS_SECRET_ACCESS_KEY" 14 | "AWS_KEY" 15 | "AWS_SECRET" 16 | "PASSPORT_PASSWORD_GRANT_CLIENT_ID" 17 | "PASSPORT_PASSWORD_GRANT_CLIENT_SECRET" 18 | "SENTRY_AUTH_TOKEN" 19 | "LOCATION_IQ_API_KEY" 20 | "WEATHERAPI_KEY" 21 | "IPDATA_TOKEN" 22 | ) 23 | 24 | for secret in "${supportedSecrets[@]}"; do 25 | envFile="${secret}_FILE" 26 | if [ -n "${!envFile}" ] && [ -f "${!envFile}" ]; then 27 | val="$(< "${!envFile}")" 28 | export "${secret}"="$val" 29 | echo "${secret} environment variable was set by secret ${envFile}" 30 | fi 31 | done 32 | 33 | # wait for the database to start 34 | waitfordb() { 35 | TERM=dumb php -- <<'EOPHP' 36 | 0); 79 | 80 | if ($maxAttempts <= 0 || $mysql === null) { 81 | fwrite($stderr, "\n" . 'Unable to contact your database'); 82 | if ($mysql !== null) { 83 | fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); 84 | $mysql->close(); 85 | } 86 | exit(1); 87 | } 88 | 89 | fwrite($stderr, "\n" . 'Database ready.'); 90 | 91 | $createDatabase = $mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($database) . '` CHARACTER SET ' . $collation[0] . ' COLLATE ' . $collation[1]); 92 | if ($createDatabase === false) { 93 | fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); 94 | $mysql->close(); 95 | exit(2); 96 | } 97 | 98 | $mysql->close(); 99 | EOPHP 100 | } 101 | 102 | if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ]; then 103 | 104 | MONICADIR=/var/www/html 105 | ARTISAN="php ${MONICADIR}/artisan" 106 | 107 | # Ensure storage directories are present 108 | STORAGE=${MONICADIR}/storage 109 | mkdir -p ${STORAGE}/logs 110 | mkdir -p ${STORAGE}/app/public 111 | mkdir -p ${STORAGE}/framework/views 112 | mkdir -p ${STORAGE}/framework/cache 113 | mkdir -p ${STORAGE}/framework/sessions 114 | chown -R www-data:www-data ${STORAGE} 115 | chmod -R g+rw ${STORAGE} 116 | 117 | if [ -z "${APP_KEY:-}" -o "$APP_KEY" = "ChangeMeBy32KeyLengthOrGenerated" ]; then 118 | ${ARTISAN} key:generate --no-interaction 119 | else 120 | echo "APP_KEY already set" 121 | fi 122 | 123 | # Run migrations 124 | waitfordb 125 | ${ARTISAN} monica:update --force -vv 126 | 127 | if [ ! -f "${STORAGE}/oauth-public.key" -o ! -f "${STORAGE}/oauth-private.key" ]; then 128 | echo "Passport keys creation ..." 129 | ${ARTISAN} passport:keys 130 | ${ARTISAN} passport:client --personal --no-interaction 131 | echo "! Please be careful to backup $MONICADIR/storage/oauth-public.key and $MONICADIR/storage/oauth-private.key files !" 132 | fi 133 | 134 | fi 135 | 136 | exec "$@" 137 | -------------------------------------------------------------------------------- /.templates/scripts/4/queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec php /var/www/html/artisan queue:work --sleep=10 --timeout=0 --tries=3 --queue=default,migration >/proc/1/fd/1 2>/proc/1/fd/2 5 | -------------------------------------------------------------------------------- /.templates/scripts/5/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec busybox crond -f -l 0 -L /proc/1/fd/1 5 | -------------------------------------------------------------------------------- /.templates/scripts/5/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -Eeo pipefail 4 | 5 | # set environment variables with docker secrets in /run/secrets/* 6 | supportedSecrets=( "DB_PASSWORD" 7 | "DATABASE_URL" 8 | "APP_KEY" 9 | "MAIL_PASSWORD" 10 | "REDIS_PASSWORD" 11 | "AWS_ACCESS_KEY_ID" 12 | "AWS_SECRET_ACCESS_KEY" 13 | "AWS_KEY" 14 | "AWS_SECRET" 15 | "LOCATION_IQ_API_KEY" 16 | "WEATHERAPI_KEY" 17 | "MAPBOX_API_KEY" 18 | ) 19 | 20 | for secret in "${supportedSecrets[@]}"; do 21 | envFile="${secret}_FILE" 22 | if [ -n "${!envFile}" ] && [ -f "${!envFile}" ]; then 23 | val="$(< "${!envFile}")" 24 | export "${secret}"="$val" 25 | echo "${secret} environment variable was set by secret ${envFile}" 26 | fi 27 | done 28 | 29 | if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ]; then 30 | 31 | MONICADIR=/var/www/html 32 | ARTISAN="php ${MONICADIR}/artisan" 33 | 34 | # Ensure storage directories are present 35 | STORAGE=${MONICADIR}/storage 36 | mkdir -p ${STORAGE}/logs 37 | mkdir -p ${STORAGE}/app/public 38 | mkdir -p ${STORAGE}/framework/views 39 | mkdir -p ${STORAGE}/framework/cache 40 | mkdir -p ${STORAGE}/framework/sessions 41 | chown -R www-data:www-data ${STORAGE} 42 | chmod -R g+rw ${STORAGE} 43 | 44 | if [ "${DB_CONNECTION:-sqlite}" == "sqlite" ]; then 45 | dbPath="${DB_DATABASE:-database/database.sqlite}" 46 | if [ ! -f "$dbPath" ]; then 47 | echo "Creating sqlite database at ${dbPath} — make sure it will be saved in a persistent volume." 48 | touch "$dbPath" 49 | chown www-data:www-data "$dbPath" 50 | fi 51 | fi 52 | 53 | if [ -z "${APP_KEY:-}" ]; then 54 | ${ARTISAN} key:generate --no-interaction 55 | key=$(grep APP_KEY .env | cut -c 9-) 56 | echo "APP_KEY generated: $key — save it for later usage." 57 | else 58 | echo "APP_KEY already set." 59 | fi 60 | 61 | # Run migrations 62 | ${ARTISAN} waitfordb 63 | ${ARTISAN} monica:setup --force -vv 64 | 65 | fi 66 | 67 | exec "$@" 68 | -------------------------------------------------------------------------------- /.templates/scripts/5/env.production: -------------------------------------------------------------------------------- 1 | APP_NAME=Monica 2 | APP_ENV=production 3 | APP_KEY= 4 | APP_DEBUG=false 5 | APP_URL=https://monica.test 6 | 7 | # Database to store information 8 | DB_CONNECTION=sqlite 9 | # DB_DATABASE=/var/www/html/storage/database.sqlite 10 | 11 | # Drivers 12 | CACHE_STORE=database 13 | QUEUE_CONNECTION=sync 14 | SESSION_DRIVER=database 15 | 16 | # Search 17 | SCOUT_DRIVER=database 18 | SCOUT_QUEUE=false 19 | 20 | # Log 21 | LOG_CHANNEL=stderr 22 | -------------------------------------------------------------------------------- /.templates/scripts/5/queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec php /var/www/html/artisan queue:work --sleep=10 --timeout=0 --tries=3 --queue=high,default,low >/proc/1/fd/1 2>/proc/1/fd/2 5 | -------------------------------------------------------------------------------- /4/apache/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.2-apache 2 | 3 | # opencontainers annotations https://github.com/opencontainers/image-spec/blob/master/annotations.md 4 | LABEL org.opencontainers.image.authors="Alexis Saettler " \ 5 | org.opencontainers.image.title="MonicaHQ, the Personal Relationship Manager" \ 6 | org.opencontainers.image.description="This is MonicaHQ, your personal memory! MonicaHQ is like a CRM but for the friends, family, and acquaintances around you." \ 7 | org.opencontainers.image.url="https://monicahq.com" \ 8 | org.opencontainers.image.source="https://github.com/monicahq/docker" \ 9 | org.opencontainers.image.vendor="Monica" 10 | 11 | # entrypoint.sh dependencies 12 | RUN set -ex; \ 13 | \ 14 | apt-get update; \ 15 | apt-get install -y --no-install-recommends \ 16 | bash \ 17 | busybox-static \ 18 | ; \ 19 | rm -rf /var/lib/apt/lists/* 20 | 21 | # Install required PHP extensions 22 | RUN set -ex; \ 23 | \ 24 | savedAptMark="$(apt-mark showmanual)"; \ 25 | \ 26 | apt-get update; \ 27 | apt-get install -y --no-install-recommends \ 28 | libicu-dev \ 29 | zlib1g-dev \ 30 | libzip-dev \ 31 | libpng-dev \ 32 | libpq-dev \ 33 | libxml2-dev \ 34 | libfreetype6-dev \ 35 | libjpeg62-turbo-dev \ 36 | libgmp-dev \ 37 | libmemcached-dev \ 38 | libssl-dev \ 39 | libwebp-dev \ 40 | libcurl4-openssl-dev \ 41 | ; \ 42 | \ 43 | debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ 44 | if [ ! -e /usr/include/gmp.h ]; then ln -s /usr/include/$debMultiarch/gmp.h /usr/include/gmp.h; fi;\ 45 | docker-php-ext-configure intl; \ 46 | docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \ 47 | docker-php-ext-configure gmp; \ 48 | docker-php-ext-install -j$(nproc) \ 49 | intl \ 50 | zip \ 51 | bcmath \ 52 | gd \ 53 | gmp \ 54 | pdo_mysql \ 55 | mysqli \ 56 | pdo_pgsql \ 57 | soap \ 58 | ; \ 59 | \ 60 | # pecl will claim success even if one install fails, so we need to perform each install separately 61 | pecl install APCu-5.1.24; \ 62 | pecl install memcached-3.3.0; \ 63 | pecl install redis-6.2.0; \ 64 | \ 65 | docker-php-ext-enable \ 66 | apcu \ 67 | memcached \ 68 | redis \ 69 | ; \ 70 | \ 71 | # reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies 72 | apt-mark auto '.*' > /dev/null; \ 73 | apt-mark manual $savedAptMark; \ 74 | ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ 75 | | awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); print so }' \ 76 | | sort -u \ 77 | | xargs -r dpkg-query -S \ 78 | | cut -d: -f1 \ 79 | | sort -u \ 80 | | xargs -rt apt-mark manual; \ 81 | \ 82 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ 83 | rm -rf /var/lib/apt/lists/* 84 | 85 | # Set crontab for schedules 86 | RUN set -ex; \ 87 | \ 88 | mkdir -p /var/spool/cron/crontabs; \ 89 | rm -f /var/spool/cron/crontabs/root; \ 90 | echo '* * * * * php /var/www/html/artisan schedule:run -v' > /var/spool/cron/crontabs/www-data 91 | 92 | # Opcache 93 | ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \ 94 | PHP_OPCACHE_MAX_ACCELERATED_FILES="20000" \ 95 | PHP_OPCACHE_MEMORY_CONSUMPTION="192" \ 96 | PHP_OPCACHE_MAX_WASTED_PERCENTAGE="10" 97 | # Limits 98 | ENV PHP_MEMORY_LIMIT="512M" \ 99 | PHP_UPLOAD_LIMIT="512M" 100 | RUN set -ex; \ 101 | \ 102 | docker-php-ext-enable opcache; \ 103 | { \ 104 | echo '[opcache]'; \ 105 | echo 'opcache.enable=1'; \ 106 | echo 'opcache.revalidate_freq=0'; \ 107 | echo 'opcache.validate_timestamps=${PHP_OPCACHE_VALIDATE_TIMESTAMPS}'; \ 108 | echo 'opcache.max_accelerated_files=${PHP_OPCACHE_MAX_ACCELERATED_FILES}'; \ 109 | echo 'opcache.memory_consumption=${PHP_OPCACHE_MEMORY_CONSUMPTION}'; \ 110 | echo 'opcache.max_wasted_percentage=${PHP_OPCACHE_MAX_WASTED_PERCENTAGE}'; \ 111 | echo 'opcache.interned_strings_buffer=16'; \ 112 | echo 'opcache.fast_shutdown=1'; \ 113 | } > $PHP_INI_DIR/conf.d/opcache-recommended.ini; \ 114 | \ 115 | echo 'apc.enable_cli=1' >> $PHP_INI_DIR/conf.d/docker-php-ext-apcu.ini; \ 116 | \ 117 | { \ 118 | echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \ 119 | echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \ 120 | echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \ 121 | } > $PHP_INI_DIR/conf.d/limits.ini; 122 | 123 | RUN set -ex; \ 124 | \ 125 | a2enmod headers rewrite remoteip; \ 126 | { \ 127 | echo RemoteIPHeader X-Real-IP; \ 128 | echo RemoteIPTrustedProxy 10.0.0.0/8; \ 129 | echo RemoteIPTrustedProxy 172.16.0.0/12; \ 130 | echo RemoteIPTrustedProxy 192.168.0.0/16; \ 131 | } > $APACHE_CONFDIR/conf-available/remoteip.conf; \ 132 | a2enconf remoteip 133 | 134 | # set apache config LimitRequestBody 135 | ENV APACHE_BODY_LIMIT 1073741824 136 | RUN set -ex; \ 137 | \ 138 | { \ 139 | echo 'LimitRequestBody ${APACHE_BODY_LIMIT}'; \ 140 | } > $APACHE_CONFDIR/conf-available/apache-limits.conf; \ 141 | a2enconf apache-limits 142 | 143 | RUN set -ex; \ 144 | APACHE_DOCUMENT_ROOT=/var/www/html/public; \ 145 | sed -ri -e "s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g" $APACHE_CONFDIR/sites-available/*.conf; \ 146 | sed -ri -e "s!/var/www/!${APACHE_DOCUMENT_ROOT}!g" $APACHE_CONFDIR/apache2.conf $APACHE_CONFDIR/conf-available/*.conf 147 | 148 | WORKDIR /var/www/html 149 | 150 | # Define Monica version 151 | ENV MONICA_VERSION v4.1.2 152 | LABEL org.opencontainers.image.revision="32028ce3ce79cef38df5d27a297e5b20680f0065" \ 153 | org.opencontainers.image.version="v4.1.2" 154 | 155 | RUN set -ex; \ 156 | fetchDeps=" \ 157 | gnupg \ 158 | dirmngr \ 159 | "; \ 160 | apt-get update; \ 161 | apt-get install -y --no-install-recommends $fetchDeps; \ 162 | \ 163 | for ext in tar.bz2 tar.bz2.asc; do \ 164 | curl -fsSL -o monica-${MONICA_VERSION}.$ext "https://github.com/monicahq/monica/releases/download/${MONICA_VERSION}/monica-${MONICA_VERSION}.$ext"; \ 165 | done; \ 166 | \ 167 | GPGKEY='BDAB0D0D36A00466A2964E85DE15667131EA6018'; \ 168 | export GNUPGHOME="$(mktemp -d)"; \ 169 | gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$GPGKEY"; \ 170 | gpg --batch --verify monica-${MONICA_VERSION}.tar.bz2.asc monica-${MONICA_VERSION}.tar.bz2; \ 171 | \ 172 | tar -xf monica-${MONICA_VERSION}.tar.bz2 -C /var/www/html --strip-components=1; \ 173 | \ 174 | gpgconf --kill all; \ 175 | rm -rf "$GNUPGHOME" monica-${MONICA_VERSION}.tar.bz2 monica-${MONICA_VERSION}.tar.bz2.asc; \ 176 | \ 177 | cp /var/www/html/.env.example /var/www/html/.env; \ 178 | chown -R www-data:www-data /var/www/html; \ 179 | \ 180 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ 181 | rm -rf /var/lib/apt/lists/* 182 | 183 | COPY entrypoint.sh \ 184 | queue.sh \ 185 | cron.sh \ 186 | /usr/local/bin/ 187 | 188 | ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] 189 | CMD ["apache2-foreground"] 190 | -------------------------------------------------------------------------------- /4/apache/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec busybox crond -f -l 0 -L /proc/1/fd/1 5 | -------------------------------------------------------------------------------- /4/apache/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -Eeo pipefail 4 | 5 | # set environment variables with docker secrets in /run/secrets/* 6 | supportedSecrets=( "DB_PASSWORD" 7 | "DATABASE_URL" 8 | "APP_KEY" 9 | "HASH_SALT" 10 | "MAIL_PASSWORD" 11 | "REDIS_PASSWORD" 12 | "AWS_ACCESS_KEY_ID" 13 | "AWS_SECRET_ACCESS_KEY" 14 | "AWS_KEY" 15 | "AWS_SECRET" 16 | "PASSPORT_PASSWORD_GRANT_CLIENT_ID" 17 | "PASSPORT_PASSWORD_GRANT_CLIENT_SECRET" 18 | "SENTRY_AUTH_TOKEN" 19 | "LOCATION_IQ_API_KEY" 20 | "WEATHERAPI_KEY" 21 | "IPDATA_TOKEN" 22 | ) 23 | 24 | for secret in "${supportedSecrets[@]}"; do 25 | envFile="${secret}_FILE" 26 | if [ -n "${!envFile}" ] && [ -f "${!envFile}" ]; then 27 | val="$(< "${!envFile}")" 28 | export "${secret}"="$val" 29 | echo "${secret} environment variable was set by secret ${envFile}" 30 | fi 31 | done 32 | 33 | # wait for the database to start 34 | waitfordb() { 35 | TERM=dumb php -- <<'EOPHP' 36 | 0); 79 | 80 | if ($maxAttempts <= 0 || $mysql === null) { 81 | fwrite($stderr, "\n" . 'Unable to contact your database'); 82 | if ($mysql !== null) { 83 | fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); 84 | $mysql->close(); 85 | } 86 | exit(1); 87 | } 88 | 89 | fwrite($stderr, "\n" . 'Database ready.'); 90 | 91 | $createDatabase = $mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($database) . '` CHARACTER SET ' . $collation[0] . ' COLLATE ' . $collation[1]); 92 | if ($createDatabase === false) { 93 | fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); 94 | $mysql->close(); 95 | exit(2); 96 | } 97 | 98 | $mysql->close(); 99 | EOPHP 100 | } 101 | 102 | if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ]; then 103 | 104 | MONICADIR=/var/www/html 105 | ARTISAN="php ${MONICADIR}/artisan" 106 | 107 | # Ensure storage directories are present 108 | STORAGE=${MONICADIR}/storage 109 | mkdir -p ${STORAGE}/logs 110 | mkdir -p ${STORAGE}/app/public 111 | mkdir -p ${STORAGE}/framework/views 112 | mkdir -p ${STORAGE}/framework/cache 113 | mkdir -p ${STORAGE}/framework/sessions 114 | chown -R www-data:www-data ${STORAGE} 115 | chmod -R g+rw ${STORAGE} 116 | 117 | if [ -z "${APP_KEY:-}" -o "$APP_KEY" = "ChangeMeBy32KeyLengthOrGenerated" ]; then 118 | ${ARTISAN} key:generate --no-interaction 119 | else 120 | echo "APP_KEY already set" 121 | fi 122 | 123 | # Run migrations 124 | waitfordb 125 | ${ARTISAN} monica:update --force -vv 126 | 127 | if [ ! -f "${STORAGE}/oauth-public.key" -o ! -f "${STORAGE}/oauth-private.key" ]; then 128 | echo "Passport keys creation ..." 129 | ${ARTISAN} passport:keys 130 | ${ARTISAN} passport:client --personal --no-interaction 131 | echo "! Please be careful to backup $MONICADIR/storage/oauth-public.key and $MONICADIR/storage/oauth-private.key files !" 132 | fi 133 | 134 | fi 135 | 136 | exec "$@" 137 | -------------------------------------------------------------------------------- /4/apache/queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec php /var/www/html/artisan queue:work --sleep=10 --timeout=0 --tries=3 --queue=default,migration >/proc/1/fd/1 2>/proc/1/fd/2 5 | -------------------------------------------------------------------------------- /4/fpm-alpine/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.2-fpm-alpine 2 | 3 | # opencontainers annotations https://github.com/opencontainers/image-spec/blob/master/annotations.md 4 | LABEL org.opencontainers.image.authors="Alexis Saettler " \ 5 | org.opencontainers.image.title="MonicaHQ, the Personal Relationship Manager" \ 6 | org.opencontainers.image.description="This is MonicaHQ, your personal memory! MonicaHQ is like a CRM but for the friends, family, and acquaintances around you." \ 7 | org.opencontainers.image.url="https://monicahq.com" \ 8 | org.opencontainers.image.source="https://github.com/monicahq/docker" \ 9 | org.opencontainers.image.vendor="Monica" 10 | 11 | # entrypoint.sh dependencies 12 | RUN set -ex; \ 13 | \ 14 | apk add --no-cache \ 15 | bash \ 16 | coreutils 17 | 18 | # Install required PHP extensions 19 | RUN set -ex; \ 20 | \ 21 | apk add --no-cache --virtual .build-deps \ 22 | $PHPIZE_DEPS \ 23 | icu-dev \ 24 | zlib-dev \ 25 | libzip-dev \ 26 | libxml2-dev \ 27 | freetype-dev \ 28 | libpng-dev \ 29 | libpq-dev \ 30 | libjpeg-turbo-dev \ 31 | jpeg-dev \ 32 | gmp-dev \ 33 | libmemcached-dev \ 34 | libwebp-dev \ 35 | ; \ 36 | \ 37 | docker-php-ext-configure intl; \ 38 | docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \ 39 | docker-php-ext-configure gmp; \ 40 | docker-php-ext-install -j "$(nproc)" \ 41 | intl \ 42 | zip \ 43 | bcmath \ 44 | gd \ 45 | gmp \ 46 | pdo_mysql \ 47 | mysqli \ 48 | pdo_pgsql \ 49 | soap \ 50 | ; \ 51 | # pecl will claim success even if one install fails, so we need to perform each install separately 52 | pecl install APCu-5.1.24; \ 53 | pecl install memcached-3.3.0; \ 54 | pecl install redis-6.2.0; \ 55 | \ 56 | docker-php-ext-enable \ 57 | apcu \ 58 | memcached \ 59 | redis \ 60 | ; \ 61 | \ 62 | runDeps="$( \ 63 | scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ 64 | | tr ',' '\n' \ 65 | | sort -u \ 66 | | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ 67 | )"; \ 68 | apk add --no-network --virtual .monica-phpext-rundeps $runDeps; \ 69 | apk del --no-network .build-deps 70 | 71 | # Set crontab for schedules 72 | RUN set -ex; \ 73 | \ 74 | mkdir -p /var/spool/cron/crontabs; \ 75 | rm -f /var/spool/cron/crontabs/root; \ 76 | echo '* * * * * php /var/www/html/artisan schedule:run -v' > /var/spool/cron/crontabs/www-data 77 | 78 | # Opcache 79 | ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \ 80 | PHP_OPCACHE_MAX_ACCELERATED_FILES="20000" \ 81 | PHP_OPCACHE_MEMORY_CONSUMPTION="192" \ 82 | PHP_OPCACHE_MAX_WASTED_PERCENTAGE="10" 83 | # Limits 84 | ENV PHP_MEMORY_LIMIT="512M" \ 85 | PHP_UPLOAD_LIMIT="512M" 86 | RUN set -ex; \ 87 | \ 88 | docker-php-ext-enable opcache; \ 89 | { \ 90 | echo '[opcache]'; \ 91 | echo 'opcache.enable=1'; \ 92 | echo 'opcache.revalidate_freq=0'; \ 93 | echo 'opcache.validate_timestamps=${PHP_OPCACHE_VALIDATE_TIMESTAMPS}'; \ 94 | echo 'opcache.max_accelerated_files=${PHP_OPCACHE_MAX_ACCELERATED_FILES}'; \ 95 | echo 'opcache.memory_consumption=${PHP_OPCACHE_MEMORY_CONSUMPTION}'; \ 96 | echo 'opcache.max_wasted_percentage=${PHP_OPCACHE_MAX_WASTED_PERCENTAGE}'; \ 97 | echo 'opcache.interned_strings_buffer=16'; \ 98 | echo 'opcache.fast_shutdown=1'; \ 99 | } > $PHP_INI_DIR/conf.d/opcache-recommended.ini; \ 100 | \ 101 | echo 'apc.enable_cli=1' >> $PHP_INI_DIR/conf.d/docker-php-ext-apcu.ini; \ 102 | \ 103 | { \ 104 | echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \ 105 | echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \ 106 | echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \ 107 | } > $PHP_INI_DIR/conf.d/limits.ini; 108 | 109 | 110 | 111 | WORKDIR /var/www/html 112 | 113 | # Define Monica version 114 | ENV MONICA_VERSION v4.1.2 115 | LABEL org.opencontainers.image.revision="32028ce3ce79cef38df5d27a297e5b20680f0065" \ 116 | org.opencontainers.image.version="v4.1.2" 117 | 118 | RUN set -ex; \ 119 | apk add --no-cache --virtual .fetch-deps \ 120 | bzip2 \ 121 | gnupg \ 122 | ; \ 123 | \ 124 | for ext in tar.bz2 tar.bz2.asc; do \ 125 | curl -fsSL -o monica-${MONICA_VERSION}.$ext "https://github.com/monicahq/monica/releases/download/${MONICA_VERSION}/monica-${MONICA_VERSION}.$ext"; \ 126 | done; \ 127 | \ 128 | GPGKEY='BDAB0D0D36A00466A2964E85DE15667131EA6018'; \ 129 | export GNUPGHOME="$(mktemp -d)"; \ 130 | gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$GPGKEY"; \ 131 | gpg --batch --verify monica-${MONICA_VERSION}.tar.bz2.asc monica-${MONICA_VERSION}.tar.bz2; \ 132 | \ 133 | tar -xf monica-${MONICA_VERSION}.tar.bz2 -C /var/www/html --strip-components=1; \ 134 | \ 135 | gpgconf --kill all; \ 136 | rm -rf "$GNUPGHOME" monica-${MONICA_VERSION}.tar.bz2 monica-${MONICA_VERSION}.tar.bz2.asc; \ 137 | \ 138 | cp /var/www/html/.env.example /var/www/html/.env; \ 139 | chown -R www-data:www-data /var/www/html; \ 140 | \ 141 | apk del .fetch-deps 142 | 143 | COPY entrypoint.sh \ 144 | queue.sh \ 145 | cron.sh \ 146 | /usr/local/bin/ 147 | 148 | ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] 149 | CMD ["php-fpm"] 150 | -------------------------------------------------------------------------------- /4/fpm-alpine/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec busybox crond -f -l 0 -L /proc/1/fd/1 5 | -------------------------------------------------------------------------------- /4/fpm-alpine/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -Eeo pipefail 4 | 5 | # set environment variables with docker secrets in /run/secrets/* 6 | supportedSecrets=( "DB_PASSWORD" 7 | "DATABASE_URL" 8 | "APP_KEY" 9 | "HASH_SALT" 10 | "MAIL_PASSWORD" 11 | "REDIS_PASSWORD" 12 | "AWS_ACCESS_KEY_ID" 13 | "AWS_SECRET_ACCESS_KEY" 14 | "AWS_KEY" 15 | "AWS_SECRET" 16 | "PASSPORT_PASSWORD_GRANT_CLIENT_ID" 17 | "PASSPORT_PASSWORD_GRANT_CLIENT_SECRET" 18 | "SENTRY_AUTH_TOKEN" 19 | "LOCATION_IQ_API_KEY" 20 | "WEATHERAPI_KEY" 21 | "IPDATA_TOKEN" 22 | ) 23 | 24 | for secret in "${supportedSecrets[@]}"; do 25 | envFile="${secret}_FILE" 26 | if [ -n "${!envFile}" ] && [ -f "${!envFile}" ]; then 27 | val="$(< "${!envFile}")" 28 | export "${secret}"="$val" 29 | echo "${secret} environment variable was set by secret ${envFile}" 30 | fi 31 | done 32 | 33 | # wait for the database to start 34 | waitfordb() { 35 | TERM=dumb php -- <<'EOPHP' 36 | 0); 79 | 80 | if ($maxAttempts <= 0 || $mysql === null) { 81 | fwrite($stderr, "\n" . 'Unable to contact your database'); 82 | if ($mysql !== null) { 83 | fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); 84 | $mysql->close(); 85 | } 86 | exit(1); 87 | } 88 | 89 | fwrite($stderr, "\n" . 'Database ready.'); 90 | 91 | $createDatabase = $mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($database) . '` CHARACTER SET ' . $collation[0] . ' COLLATE ' . $collation[1]); 92 | if ($createDatabase === false) { 93 | fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); 94 | $mysql->close(); 95 | exit(2); 96 | } 97 | 98 | $mysql->close(); 99 | EOPHP 100 | } 101 | 102 | if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ]; then 103 | 104 | MONICADIR=/var/www/html 105 | ARTISAN="php ${MONICADIR}/artisan" 106 | 107 | # Ensure storage directories are present 108 | STORAGE=${MONICADIR}/storage 109 | mkdir -p ${STORAGE}/logs 110 | mkdir -p ${STORAGE}/app/public 111 | mkdir -p ${STORAGE}/framework/views 112 | mkdir -p ${STORAGE}/framework/cache 113 | mkdir -p ${STORAGE}/framework/sessions 114 | chown -R www-data:www-data ${STORAGE} 115 | chmod -R g+rw ${STORAGE} 116 | 117 | if [ -z "${APP_KEY:-}" -o "$APP_KEY" = "ChangeMeBy32KeyLengthOrGenerated" ]; then 118 | ${ARTISAN} key:generate --no-interaction 119 | else 120 | echo "APP_KEY already set" 121 | fi 122 | 123 | # Run migrations 124 | waitfordb 125 | ${ARTISAN} monica:update --force -vv 126 | 127 | if [ ! -f "${STORAGE}/oauth-public.key" -o ! -f "${STORAGE}/oauth-private.key" ]; then 128 | echo "Passport keys creation ..." 129 | ${ARTISAN} passport:keys 130 | ${ARTISAN} passport:client --personal --no-interaction 131 | echo "! Please be careful to backup $MONICADIR/storage/oauth-public.key and $MONICADIR/storage/oauth-private.key files !" 132 | fi 133 | 134 | fi 135 | 136 | exec "$@" 137 | -------------------------------------------------------------------------------- /4/fpm-alpine/queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec php /var/www/html/artisan queue:work --sleep=10 --timeout=0 --tries=3 --queue=default,migration >/proc/1/fd/1 2>/proc/1/fd/2 5 | -------------------------------------------------------------------------------- /4/fpm/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.2-fpm 2 | 3 | # opencontainers annotations https://github.com/opencontainers/image-spec/blob/master/annotations.md 4 | LABEL org.opencontainers.image.authors="Alexis Saettler " \ 5 | org.opencontainers.image.title="MonicaHQ, the Personal Relationship Manager" \ 6 | org.opencontainers.image.description="This is MonicaHQ, your personal memory! MonicaHQ is like a CRM but for the friends, family, and acquaintances around you." \ 7 | org.opencontainers.image.url="https://monicahq.com" \ 8 | org.opencontainers.image.source="https://github.com/monicahq/docker" \ 9 | org.opencontainers.image.vendor="Monica" 10 | 11 | # entrypoint.sh dependencies 12 | RUN set -ex; \ 13 | \ 14 | apt-get update; \ 15 | apt-get install -y --no-install-recommends \ 16 | bash \ 17 | busybox-static \ 18 | ; \ 19 | rm -rf /var/lib/apt/lists/* 20 | 21 | # Install required PHP extensions 22 | RUN set -ex; \ 23 | \ 24 | savedAptMark="$(apt-mark showmanual)"; \ 25 | \ 26 | apt-get update; \ 27 | apt-get install -y --no-install-recommends \ 28 | libicu-dev \ 29 | zlib1g-dev \ 30 | libzip-dev \ 31 | libpng-dev \ 32 | libpq-dev \ 33 | libxml2-dev \ 34 | libfreetype6-dev \ 35 | libjpeg62-turbo-dev \ 36 | libgmp-dev \ 37 | libmemcached-dev \ 38 | libssl-dev \ 39 | libwebp-dev \ 40 | libcurl4-openssl-dev \ 41 | ; \ 42 | \ 43 | debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ 44 | if [ ! -e /usr/include/gmp.h ]; then ln -s /usr/include/$debMultiarch/gmp.h /usr/include/gmp.h; fi;\ 45 | docker-php-ext-configure intl; \ 46 | docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \ 47 | docker-php-ext-configure gmp; \ 48 | docker-php-ext-install -j$(nproc) \ 49 | intl \ 50 | zip \ 51 | bcmath \ 52 | gd \ 53 | gmp \ 54 | pdo_mysql \ 55 | mysqli \ 56 | pdo_pgsql \ 57 | soap \ 58 | ; \ 59 | \ 60 | # pecl will claim success even if one install fails, so we need to perform each install separately 61 | pecl install APCu-5.1.24; \ 62 | pecl install memcached-3.3.0; \ 63 | pecl install redis-6.2.0; \ 64 | \ 65 | docker-php-ext-enable \ 66 | apcu \ 67 | memcached \ 68 | redis \ 69 | ; \ 70 | \ 71 | # reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies 72 | apt-mark auto '.*' > /dev/null; \ 73 | apt-mark manual $savedAptMark; \ 74 | ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ 75 | | awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); print so }' \ 76 | | sort -u \ 77 | | xargs -r dpkg-query -S \ 78 | | cut -d: -f1 \ 79 | | sort -u \ 80 | | xargs -rt apt-mark manual; \ 81 | \ 82 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ 83 | rm -rf /var/lib/apt/lists/* 84 | 85 | # Set crontab for schedules 86 | RUN set -ex; \ 87 | \ 88 | mkdir -p /var/spool/cron/crontabs; \ 89 | rm -f /var/spool/cron/crontabs/root; \ 90 | echo '* * * * * php /var/www/html/artisan schedule:run -v' > /var/spool/cron/crontabs/www-data 91 | 92 | # Opcache 93 | ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \ 94 | PHP_OPCACHE_MAX_ACCELERATED_FILES="20000" \ 95 | PHP_OPCACHE_MEMORY_CONSUMPTION="192" \ 96 | PHP_OPCACHE_MAX_WASTED_PERCENTAGE="10" 97 | # Limits 98 | ENV PHP_MEMORY_LIMIT="512M" \ 99 | PHP_UPLOAD_LIMIT="512M" 100 | RUN set -ex; \ 101 | \ 102 | docker-php-ext-enable opcache; \ 103 | { \ 104 | echo '[opcache]'; \ 105 | echo 'opcache.enable=1'; \ 106 | echo 'opcache.revalidate_freq=0'; \ 107 | echo 'opcache.validate_timestamps=${PHP_OPCACHE_VALIDATE_TIMESTAMPS}'; \ 108 | echo 'opcache.max_accelerated_files=${PHP_OPCACHE_MAX_ACCELERATED_FILES}'; \ 109 | echo 'opcache.memory_consumption=${PHP_OPCACHE_MEMORY_CONSUMPTION}'; \ 110 | echo 'opcache.max_wasted_percentage=${PHP_OPCACHE_MAX_WASTED_PERCENTAGE}'; \ 111 | echo 'opcache.interned_strings_buffer=16'; \ 112 | echo 'opcache.fast_shutdown=1'; \ 113 | } > $PHP_INI_DIR/conf.d/opcache-recommended.ini; \ 114 | \ 115 | echo 'apc.enable_cli=1' >> $PHP_INI_DIR/conf.d/docker-php-ext-apcu.ini; \ 116 | \ 117 | { \ 118 | echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \ 119 | echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \ 120 | echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \ 121 | } > $PHP_INI_DIR/conf.d/limits.ini; 122 | 123 | 124 | 125 | WORKDIR /var/www/html 126 | 127 | # Define Monica version 128 | ENV MONICA_VERSION v4.1.2 129 | LABEL org.opencontainers.image.revision="32028ce3ce79cef38df5d27a297e5b20680f0065" \ 130 | org.opencontainers.image.version="v4.1.2" 131 | 132 | RUN set -ex; \ 133 | fetchDeps=" \ 134 | gnupg \ 135 | dirmngr \ 136 | "; \ 137 | apt-get update; \ 138 | apt-get install -y --no-install-recommends $fetchDeps; \ 139 | \ 140 | for ext in tar.bz2 tar.bz2.asc; do \ 141 | curl -fsSL -o monica-${MONICA_VERSION}.$ext "https://github.com/monicahq/monica/releases/download/${MONICA_VERSION}/monica-${MONICA_VERSION}.$ext"; \ 142 | done; \ 143 | \ 144 | GPGKEY='BDAB0D0D36A00466A2964E85DE15667131EA6018'; \ 145 | export GNUPGHOME="$(mktemp -d)"; \ 146 | gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$GPGKEY"; \ 147 | gpg --batch --verify monica-${MONICA_VERSION}.tar.bz2.asc monica-${MONICA_VERSION}.tar.bz2; \ 148 | \ 149 | tar -xf monica-${MONICA_VERSION}.tar.bz2 -C /var/www/html --strip-components=1; \ 150 | \ 151 | gpgconf --kill all; \ 152 | rm -rf "$GNUPGHOME" monica-${MONICA_VERSION}.tar.bz2 monica-${MONICA_VERSION}.tar.bz2.asc; \ 153 | \ 154 | cp /var/www/html/.env.example /var/www/html/.env; \ 155 | chown -R www-data:www-data /var/www/html; \ 156 | \ 157 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ 158 | rm -rf /var/lib/apt/lists/* 159 | 160 | COPY entrypoint.sh \ 161 | queue.sh \ 162 | cron.sh \ 163 | /usr/local/bin/ 164 | 165 | ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] 166 | CMD ["php-fpm"] 167 | -------------------------------------------------------------------------------- /4/fpm/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec busybox crond -f -l 0 -L /proc/1/fd/1 5 | -------------------------------------------------------------------------------- /4/fpm/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -Eeo pipefail 4 | 5 | # set environment variables with docker secrets in /run/secrets/* 6 | supportedSecrets=( "DB_PASSWORD" 7 | "DATABASE_URL" 8 | "APP_KEY" 9 | "HASH_SALT" 10 | "MAIL_PASSWORD" 11 | "REDIS_PASSWORD" 12 | "AWS_ACCESS_KEY_ID" 13 | "AWS_SECRET_ACCESS_KEY" 14 | "AWS_KEY" 15 | "AWS_SECRET" 16 | "PASSPORT_PASSWORD_GRANT_CLIENT_ID" 17 | "PASSPORT_PASSWORD_GRANT_CLIENT_SECRET" 18 | "SENTRY_AUTH_TOKEN" 19 | "LOCATION_IQ_API_KEY" 20 | "WEATHERAPI_KEY" 21 | "IPDATA_TOKEN" 22 | ) 23 | 24 | for secret in "${supportedSecrets[@]}"; do 25 | envFile="${secret}_FILE" 26 | if [ -n "${!envFile}" ] && [ -f "${!envFile}" ]; then 27 | val="$(< "${!envFile}")" 28 | export "${secret}"="$val" 29 | echo "${secret} environment variable was set by secret ${envFile}" 30 | fi 31 | done 32 | 33 | # wait for the database to start 34 | waitfordb() { 35 | TERM=dumb php -- <<'EOPHP' 36 | 0); 79 | 80 | if ($maxAttempts <= 0 || $mysql === null) { 81 | fwrite($stderr, "\n" . 'Unable to contact your database'); 82 | if ($mysql !== null) { 83 | fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); 84 | $mysql->close(); 85 | } 86 | exit(1); 87 | } 88 | 89 | fwrite($stderr, "\n" . 'Database ready.'); 90 | 91 | $createDatabase = $mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($database) . '` CHARACTER SET ' . $collation[0] . ' COLLATE ' . $collation[1]); 92 | if ($createDatabase === false) { 93 | fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); 94 | $mysql->close(); 95 | exit(2); 96 | } 97 | 98 | $mysql->close(); 99 | EOPHP 100 | } 101 | 102 | if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ]; then 103 | 104 | MONICADIR=/var/www/html 105 | ARTISAN="php ${MONICADIR}/artisan" 106 | 107 | # Ensure storage directories are present 108 | STORAGE=${MONICADIR}/storage 109 | mkdir -p ${STORAGE}/logs 110 | mkdir -p ${STORAGE}/app/public 111 | mkdir -p ${STORAGE}/framework/views 112 | mkdir -p ${STORAGE}/framework/cache 113 | mkdir -p ${STORAGE}/framework/sessions 114 | chown -R www-data:www-data ${STORAGE} 115 | chmod -R g+rw ${STORAGE} 116 | 117 | if [ -z "${APP_KEY:-}" -o "$APP_KEY" = "ChangeMeBy32KeyLengthOrGenerated" ]; then 118 | ${ARTISAN} key:generate --no-interaction 119 | else 120 | echo "APP_KEY already set" 121 | fi 122 | 123 | # Run migrations 124 | waitfordb 125 | ${ARTISAN} monica:update --force -vv 126 | 127 | if [ ! -f "${STORAGE}/oauth-public.key" -o ! -f "${STORAGE}/oauth-private.key" ]; then 128 | echo "Passport keys creation ..." 129 | ${ARTISAN} passport:keys 130 | ${ARTISAN} passport:client --personal --no-interaction 131 | echo "! Please be careful to backup $MONICADIR/storage/oauth-public.key and $MONICADIR/storage/oauth-private.key files !" 132 | fi 133 | 134 | fi 135 | 136 | exec "$@" 137 | -------------------------------------------------------------------------------- /4/fpm/queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec php /var/www/html/artisan queue:work --sleep=10 --timeout=0 --tries=3 --queue=default,migration >/proc/1/fd/1 2>/proc/1/fd/2 5 | -------------------------------------------------------------------------------- /5/apache/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.3-apache 2 | 3 | # opencontainers annotations https://github.com/opencontainers/image-spec/blob/master/annotations.md 4 | LABEL org.opencontainers.image.authors="Alexis Saettler " \ 5 | org.opencontainers.image.title="MonicaHQ, the Personal Relationship Manager" \ 6 | org.opencontainers.image.description="This is MonicaHQ, your personal memory! MonicaHQ is like a CRM but for the friends, family, and acquaintances around you." \ 7 | org.opencontainers.image.url="https://monicahq.com" \ 8 | org.opencontainers.image.source="https://github.com/monicahq/docker" \ 9 | org.opencontainers.image.vendor="Monica" 10 | 11 | # entrypoint.sh dependencies 12 | RUN set -ex; \ 13 | \ 14 | apt-get update; \ 15 | apt-get install -y --no-install-recommends \ 16 | bash \ 17 | busybox-static \ 18 | ; \ 19 | rm -rf /var/lib/apt/lists/* 20 | 21 | # Install required PHP extensions 22 | RUN set -ex; \ 23 | \ 24 | savedAptMark="$(apt-mark showmanual)"; \ 25 | \ 26 | apt-get update; \ 27 | apt-get install -y --no-install-recommends \ 28 | libicu-dev \ 29 | zlib1g-dev \ 30 | libzip-dev \ 31 | libpng-dev \ 32 | libpq-dev \ 33 | libxml2-dev \ 34 | libfreetype6-dev \ 35 | libjpeg62-turbo-dev \ 36 | libgmp-dev \ 37 | libmemcached-dev \ 38 | libssl-dev \ 39 | libwebp-dev \ 40 | libcurl4-openssl-dev \ 41 | ; \ 42 | \ 43 | debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ 44 | if [ ! -e /usr/include/gmp.h ]; then ln -s /usr/include/$debMultiarch/gmp.h /usr/include/gmp.h; fi;\ 45 | docker-php-ext-configure intl; \ 46 | docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \ 47 | docker-php-ext-configure gmp; \ 48 | docker-php-ext-install -j$(nproc) \ 49 | intl \ 50 | zip \ 51 | bcmath \ 52 | gd \ 53 | gmp \ 54 | pdo_mysql \ 55 | mysqli \ 56 | pdo_pgsql \ 57 | soap \ 58 | ; \ 59 | \ 60 | # pecl will claim success even if one install fails, so we need to perform each install separately 61 | pecl install APCu-5.1.24; \ 62 | pecl install memcached-3.3.0; \ 63 | pecl install redis-6.2.0; \ 64 | \ 65 | docker-php-ext-enable \ 66 | apcu \ 67 | memcached \ 68 | redis \ 69 | ; \ 70 | \ 71 | # reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies 72 | apt-mark auto '.*' > /dev/null; \ 73 | apt-mark manual $savedAptMark; \ 74 | ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ 75 | | awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); print so }' \ 76 | | sort -u \ 77 | | xargs -r dpkg-query -S \ 78 | | cut -d: -f1 \ 79 | | sort -u \ 80 | | xargs -rt apt-mark manual; \ 81 | \ 82 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ 83 | rm -rf /var/lib/apt/lists/* 84 | 85 | # Set crontab for schedules 86 | RUN set -ex; \ 87 | \ 88 | mkdir -p /var/spool/cron/crontabs; \ 89 | rm -f /var/spool/cron/crontabs/root; \ 90 | echo '* * * * * php /var/www/html/artisan schedule:run -v' > /var/spool/cron/crontabs/www-data 91 | 92 | # Opcache 93 | ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \ 94 | PHP_OPCACHE_MAX_ACCELERATED_FILES="20000" \ 95 | PHP_OPCACHE_MEMORY_CONSUMPTION="192" \ 96 | PHP_OPCACHE_MAX_WASTED_PERCENTAGE="10" 97 | # Limits 98 | ENV PHP_MEMORY_LIMIT="512M" \ 99 | PHP_UPLOAD_LIMIT="512M" 100 | RUN set -ex; \ 101 | \ 102 | docker-php-ext-enable opcache; \ 103 | { \ 104 | echo '[opcache]'; \ 105 | echo 'opcache.enable=1'; \ 106 | echo 'opcache.revalidate_freq=0'; \ 107 | echo 'opcache.validate_timestamps=${PHP_OPCACHE_VALIDATE_TIMESTAMPS}'; \ 108 | echo 'opcache.max_accelerated_files=${PHP_OPCACHE_MAX_ACCELERATED_FILES}'; \ 109 | echo 'opcache.memory_consumption=${PHP_OPCACHE_MEMORY_CONSUMPTION}'; \ 110 | echo 'opcache.max_wasted_percentage=${PHP_OPCACHE_MAX_WASTED_PERCENTAGE}'; \ 111 | echo 'opcache.interned_strings_buffer=16'; \ 112 | echo 'opcache.fast_shutdown=1'; \ 113 | } > $PHP_INI_DIR/conf.d/opcache-recommended.ini; \ 114 | \ 115 | echo 'apc.enable_cli=1' >> $PHP_INI_DIR/conf.d/docker-php-ext-apcu.ini; \ 116 | \ 117 | { \ 118 | echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \ 119 | echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \ 120 | echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \ 121 | } > $PHP_INI_DIR/conf.d/limits.ini; 122 | 123 | RUN set -ex; \ 124 | \ 125 | a2enmod headers rewrite remoteip; \ 126 | { \ 127 | echo RemoteIPHeader X-Real-IP; \ 128 | echo RemoteIPTrustedProxy 10.0.0.0/8; \ 129 | echo RemoteIPTrustedProxy 172.16.0.0/12; \ 130 | echo RemoteIPTrustedProxy 192.168.0.0/16; \ 131 | } > $APACHE_CONFDIR/conf-available/remoteip.conf; \ 132 | a2enconf remoteip 133 | 134 | # set apache config LimitRequestBody 135 | ENV APACHE_BODY_LIMIT 1073741824 136 | RUN set -ex; \ 137 | \ 138 | { \ 139 | echo 'LimitRequestBody ${APACHE_BODY_LIMIT}'; \ 140 | } > $APACHE_CONFDIR/conf-available/apache-limits.conf; \ 141 | a2enconf apache-limits 142 | 143 | RUN set -ex; \ 144 | APACHE_DOCUMENT_ROOT=/var/www/html/public; \ 145 | sed -ri -e "s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g" $APACHE_CONFDIR/sites-available/*.conf; \ 146 | sed -ri -e "s!/var/www/!${APACHE_DOCUMENT_ROOT}!g" $APACHE_CONFDIR/apache2.conf $APACHE_CONFDIR/conf-available/*.conf 147 | 148 | WORKDIR /var/www/html 149 | 150 | # Define Monica version 151 | ENV MONICA_VERSION v5.0.0-beta.5 152 | LABEL org.opencontainers.image.revision="0c9a7dd1405f71fc46ea97f87b6c4ae67a423df3" \ 153 | org.opencontainers.image.version="v5.0.0-beta.5" 154 | 155 | RUN set -ex; \ 156 | fetchDeps=" \ 157 | gnupg \ 158 | dirmngr \ 159 | "; \ 160 | apt-get update; \ 161 | apt-get install -y --no-install-recommends $fetchDeps; \ 162 | \ 163 | for ext in tar.bz2 tar.bz2.asc; do \ 164 | curl -fsSL -o monica-${MONICA_VERSION}.$ext "https://github.com/monicahq/monica/releases/download/${MONICA_VERSION}/monica-${MONICA_VERSION}.$ext"; \ 165 | done; \ 166 | \ 167 | GPGKEY='BDAB0D0D36A00466A2964E85DE15667131EA6018'; \ 168 | export GNUPGHOME="$(mktemp -d)"; \ 169 | gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$GPGKEY"; \ 170 | gpg --batch --verify monica-${MONICA_VERSION}.tar.bz2.asc monica-${MONICA_VERSION}.tar.bz2; \ 171 | \ 172 | tar -xf monica-${MONICA_VERSION}.tar.bz2 -C /var/www/html --strip-components=1; \ 173 | \ 174 | gpgconf --kill all; \ 175 | rm -rf "$GNUPGHOME" monica-${MONICA_VERSION}.tar.bz2 monica-${MONICA_VERSION}.tar.bz2.asc; \ 176 | \ 177 | cp /var/www/html/.env.example /var/www/html/.env; \ 178 | chown -R www-data:www-data /var/www/html; \ 179 | \ 180 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ 181 | rm -rf /var/lib/apt/lists/* 182 | 183 | COPY --chown=www-data:www-data env.production .env 184 | COPY entrypoint.sh \ 185 | queue.sh \ 186 | cron.sh \ 187 | /usr/local/bin/ 188 | 189 | ENTRYPOINT ["entrypoint.sh"] 190 | CMD ["apache2-foreground"] 191 | -------------------------------------------------------------------------------- /5/apache/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec busybox crond -f -l 0 -L /proc/1/fd/1 5 | -------------------------------------------------------------------------------- /5/apache/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -Eeo pipefail 4 | 5 | # set environment variables with docker secrets in /run/secrets/* 6 | supportedSecrets=( "DB_PASSWORD" 7 | "DATABASE_URL" 8 | "APP_KEY" 9 | "MAIL_PASSWORD" 10 | "REDIS_PASSWORD" 11 | "AWS_ACCESS_KEY_ID" 12 | "AWS_SECRET_ACCESS_KEY" 13 | "AWS_KEY" 14 | "AWS_SECRET" 15 | "LOCATION_IQ_API_KEY" 16 | "WEATHERAPI_KEY" 17 | "MAPBOX_API_KEY" 18 | ) 19 | 20 | for secret in "${supportedSecrets[@]}"; do 21 | envFile="${secret}_FILE" 22 | if [ -n "${!envFile}" ] && [ -f "${!envFile}" ]; then 23 | val="$(< "${!envFile}")" 24 | export "${secret}"="$val" 25 | echo "${secret} environment variable was set by secret ${envFile}" 26 | fi 27 | done 28 | 29 | if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ]; then 30 | 31 | MONICADIR=/var/www/html 32 | ARTISAN="php ${MONICADIR}/artisan" 33 | 34 | # Ensure storage directories are present 35 | STORAGE=${MONICADIR}/storage 36 | mkdir -p ${STORAGE}/logs 37 | mkdir -p ${STORAGE}/app/public 38 | mkdir -p ${STORAGE}/framework/views 39 | mkdir -p ${STORAGE}/framework/cache 40 | mkdir -p ${STORAGE}/framework/sessions 41 | chown -R www-data:www-data ${STORAGE} 42 | chmod -R g+rw ${STORAGE} 43 | 44 | if [ "${DB_CONNECTION:-sqlite}" == "sqlite" ]; then 45 | dbPath="${DB_DATABASE:-database/database.sqlite}" 46 | if [ ! -f "$dbPath" ]; then 47 | echo "Creating sqlite database at ${dbPath} — make sure it will be saved in a persistent volume." 48 | touch "$dbPath" 49 | chown www-data:www-data "$dbPath" 50 | fi 51 | fi 52 | 53 | if [ -z "${APP_KEY:-}" ]; then 54 | ${ARTISAN} key:generate --no-interaction 55 | key=$(grep APP_KEY .env | cut -c 9-) 56 | echo "APP_KEY generated: $key — save it for later usage." 57 | else 58 | echo "APP_KEY already set." 59 | fi 60 | 61 | # Run migrations 62 | ${ARTISAN} waitfordb 63 | ${ARTISAN} monica:setup --force -vv 64 | 65 | fi 66 | 67 | exec "$@" 68 | -------------------------------------------------------------------------------- /5/apache/env.production: -------------------------------------------------------------------------------- 1 | APP_NAME=Monica 2 | APP_ENV=production 3 | APP_KEY= 4 | APP_DEBUG=false 5 | APP_URL=https://monica.test 6 | 7 | # Database to store information 8 | DB_CONNECTION=sqlite 9 | # DB_DATABASE=/var/www/html/storage/database.sqlite 10 | 11 | # Drivers 12 | CACHE_STORE=database 13 | QUEUE_CONNECTION=sync 14 | SESSION_DRIVER=database 15 | 16 | # Search 17 | SCOUT_DRIVER=database 18 | SCOUT_QUEUE=false 19 | 20 | # Log 21 | LOG_CHANNEL=stderr 22 | -------------------------------------------------------------------------------- /5/apache/queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec php /var/www/html/artisan queue:work --sleep=10 --timeout=0 --tries=3 --queue=high,default,low >/proc/1/fd/1 2>/proc/1/fd/2 5 | -------------------------------------------------------------------------------- /5/fpm-alpine/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.3-fpm-alpine 2 | 3 | # opencontainers annotations https://github.com/opencontainers/image-spec/blob/master/annotations.md 4 | LABEL org.opencontainers.image.authors="Alexis Saettler " \ 5 | org.opencontainers.image.title="MonicaHQ, the Personal Relationship Manager" \ 6 | org.opencontainers.image.description="This is MonicaHQ, your personal memory! MonicaHQ is like a CRM but for the friends, family, and acquaintances around you." \ 7 | org.opencontainers.image.url="https://monicahq.com" \ 8 | org.opencontainers.image.source="https://github.com/monicahq/docker" \ 9 | org.opencontainers.image.vendor="Monica" 10 | 11 | # entrypoint.sh dependencies 12 | RUN set -ex; \ 13 | \ 14 | apk add --no-cache \ 15 | bash \ 16 | coreutils 17 | 18 | # Install required PHP extensions 19 | RUN set -ex; \ 20 | \ 21 | apk add --no-cache --virtual .build-deps \ 22 | $PHPIZE_DEPS \ 23 | icu-dev \ 24 | zlib-dev \ 25 | libzip-dev \ 26 | libxml2-dev \ 27 | freetype-dev \ 28 | libpng-dev \ 29 | libpq-dev \ 30 | libjpeg-turbo-dev \ 31 | jpeg-dev \ 32 | gmp-dev \ 33 | libmemcached-dev \ 34 | libwebp-dev \ 35 | ; \ 36 | \ 37 | docker-php-ext-configure intl; \ 38 | docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \ 39 | docker-php-ext-configure gmp; \ 40 | docker-php-ext-install -j "$(nproc)" \ 41 | intl \ 42 | zip \ 43 | bcmath \ 44 | gd \ 45 | gmp \ 46 | pdo_mysql \ 47 | mysqli \ 48 | pdo_pgsql \ 49 | soap \ 50 | ; \ 51 | # pecl will claim success even if one install fails, so we need to perform each install separately 52 | pecl install APCu-5.1.24; \ 53 | pecl install memcached-3.3.0; \ 54 | pecl install redis-6.2.0; \ 55 | \ 56 | docker-php-ext-enable \ 57 | apcu \ 58 | memcached \ 59 | redis \ 60 | ; \ 61 | \ 62 | runDeps="$( \ 63 | scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ 64 | | tr ',' '\n' \ 65 | | sort -u \ 66 | | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ 67 | )"; \ 68 | apk add --no-network --virtual .monica-phpext-rundeps $runDeps; \ 69 | apk del --no-network .build-deps 70 | 71 | # Set crontab for schedules 72 | RUN set -ex; \ 73 | \ 74 | mkdir -p /var/spool/cron/crontabs; \ 75 | rm -f /var/spool/cron/crontabs/root; \ 76 | echo '* * * * * php /var/www/html/artisan schedule:run -v' > /var/spool/cron/crontabs/www-data 77 | 78 | # Opcache 79 | ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \ 80 | PHP_OPCACHE_MAX_ACCELERATED_FILES="20000" \ 81 | PHP_OPCACHE_MEMORY_CONSUMPTION="192" \ 82 | PHP_OPCACHE_MAX_WASTED_PERCENTAGE="10" 83 | # Limits 84 | ENV PHP_MEMORY_LIMIT="512M" \ 85 | PHP_UPLOAD_LIMIT="512M" 86 | RUN set -ex; \ 87 | \ 88 | docker-php-ext-enable opcache; \ 89 | { \ 90 | echo '[opcache]'; \ 91 | echo 'opcache.enable=1'; \ 92 | echo 'opcache.revalidate_freq=0'; \ 93 | echo 'opcache.validate_timestamps=${PHP_OPCACHE_VALIDATE_TIMESTAMPS}'; \ 94 | echo 'opcache.max_accelerated_files=${PHP_OPCACHE_MAX_ACCELERATED_FILES}'; \ 95 | echo 'opcache.memory_consumption=${PHP_OPCACHE_MEMORY_CONSUMPTION}'; \ 96 | echo 'opcache.max_wasted_percentage=${PHP_OPCACHE_MAX_WASTED_PERCENTAGE}'; \ 97 | echo 'opcache.interned_strings_buffer=16'; \ 98 | echo 'opcache.fast_shutdown=1'; \ 99 | } > $PHP_INI_DIR/conf.d/opcache-recommended.ini; \ 100 | \ 101 | echo 'apc.enable_cli=1' >> $PHP_INI_DIR/conf.d/docker-php-ext-apcu.ini; \ 102 | \ 103 | { \ 104 | echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \ 105 | echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \ 106 | echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \ 107 | } > $PHP_INI_DIR/conf.d/limits.ini; 108 | 109 | 110 | 111 | WORKDIR /var/www/html 112 | 113 | # Define Monica version 114 | ENV MONICA_VERSION v5.0.0-beta.5 115 | LABEL org.opencontainers.image.revision="0c9a7dd1405f71fc46ea97f87b6c4ae67a423df3" \ 116 | org.opencontainers.image.version="v5.0.0-beta.5" 117 | 118 | RUN set -ex; \ 119 | apk add --no-cache --virtual .fetch-deps \ 120 | bzip2 \ 121 | gnupg \ 122 | ; \ 123 | \ 124 | for ext in tar.bz2 tar.bz2.asc; do \ 125 | curl -fsSL -o monica-${MONICA_VERSION}.$ext "https://github.com/monicahq/monica/releases/download/${MONICA_VERSION}/monica-${MONICA_VERSION}.$ext"; \ 126 | done; \ 127 | \ 128 | GPGKEY='BDAB0D0D36A00466A2964E85DE15667131EA6018'; \ 129 | export GNUPGHOME="$(mktemp -d)"; \ 130 | gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$GPGKEY"; \ 131 | gpg --batch --verify monica-${MONICA_VERSION}.tar.bz2.asc monica-${MONICA_VERSION}.tar.bz2; \ 132 | \ 133 | tar -xf monica-${MONICA_VERSION}.tar.bz2 -C /var/www/html --strip-components=1; \ 134 | \ 135 | gpgconf --kill all; \ 136 | rm -rf "$GNUPGHOME" monica-${MONICA_VERSION}.tar.bz2 monica-${MONICA_VERSION}.tar.bz2.asc; \ 137 | \ 138 | cp /var/www/html/.env.example /var/www/html/.env; \ 139 | chown -R www-data:www-data /var/www/html; \ 140 | \ 141 | apk del .fetch-deps 142 | 143 | COPY --chown=www-data:www-data env.production .env 144 | COPY entrypoint.sh \ 145 | queue.sh \ 146 | cron.sh \ 147 | /usr/local/bin/ 148 | 149 | ENTRYPOINT ["entrypoint.sh"] 150 | CMD ["php-fpm"] 151 | -------------------------------------------------------------------------------- /5/fpm-alpine/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec busybox crond -f -l 0 -L /proc/1/fd/1 5 | -------------------------------------------------------------------------------- /5/fpm-alpine/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -Eeo pipefail 4 | 5 | # set environment variables with docker secrets in /run/secrets/* 6 | supportedSecrets=( "DB_PASSWORD" 7 | "DATABASE_URL" 8 | "APP_KEY" 9 | "MAIL_PASSWORD" 10 | "REDIS_PASSWORD" 11 | "AWS_ACCESS_KEY_ID" 12 | "AWS_SECRET_ACCESS_KEY" 13 | "AWS_KEY" 14 | "AWS_SECRET" 15 | "LOCATION_IQ_API_KEY" 16 | "WEATHERAPI_KEY" 17 | "MAPBOX_API_KEY" 18 | ) 19 | 20 | for secret in "${supportedSecrets[@]}"; do 21 | envFile="${secret}_FILE" 22 | if [ -n "${!envFile}" ] && [ -f "${!envFile}" ]; then 23 | val="$(< "${!envFile}")" 24 | export "${secret}"="$val" 25 | echo "${secret} environment variable was set by secret ${envFile}" 26 | fi 27 | done 28 | 29 | if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ]; then 30 | 31 | MONICADIR=/var/www/html 32 | ARTISAN="php ${MONICADIR}/artisan" 33 | 34 | # Ensure storage directories are present 35 | STORAGE=${MONICADIR}/storage 36 | mkdir -p ${STORAGE}/logs 37 | mkdir -p ${STORAGE}/app/public 38 | mkdir -p ${STORAGE}/framework/views 39 | mkdir -p ${STORAGE}/framework/cache 40 | mkdir -p ${STORAGE}/framework/sessions 41 | chown -R www-data:www-data ${STORAGE} 42 | chmod -R g+rw ${STORAGE} 43 | 44 | if [ "${DB_CONNECTION:-sqlite}" == "sqlite" ]; then 45 | dbPath="${DB_DATABASE:-database/database.sqlite}" 46 | if [ ! -f "$dbPath" ]; then 47 | echo "Creating sqlite database at ${dbPath} — make sure it will be saved in a persistent volume." 48 | touch "$dbPath" 49 | chown www-data:www-data "$dbPath" 50 | fi 51 | fi 52 | 53 | if [ -z "${APP_KEY:-}" ]; then 54 | ${ARTISAN} key:generate --no-interaction 55 | key=$(grep APP_KEY .env | cut -c 9-) 56 | echo "APP_KEY generated: $key — save it for later usage." 57 | else 58 | echo "APP_KEY already set." 59 | fi 60 | 61 | # Run migrations 62 | ${ARTISAN} waitfordb 63 | ${ARTISAN} monica:setup --force -vv 64 | 65 | fi 66 | 67 | exec "$@" 68 | -------------------------------------------------------------------------------- /5/fpm-alpine/env.production: -------------------------------------------------------------------------------- 1 | APP_NAME=Monica 2 | APP_ENV=production 3 | APP_KEY= 4 | APP_DEBUG=false 5 | APP_URL=https://monica.test 6 | 7 | # Database to store information 8 | DB_CONNECTION=sqlite 9 | # DB_DATABASE=/var/www/html/storage/database.sqlite 10 | 11 | # Drivers 12 | CACHE_STORE=database 13 | QUEUE_CONNECTION=sync 14 | SESSION_DRIVER=database 15 | 16 | # Search 17 | SCOUT_DRIVER=database 18 | SCOUT_QUEUE=false 19 | 20 | # Log 21 | LOG_CHANNEL=stderr 22 | -------------------------------------------------------------------------------- /5/fpm-alpine/queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec php /var/www/html/artisan queue:work --sleep=10 --timeout=0 --tries=3 --queue=high,default,low >/proc/1/fd/1 2>/proc/1/fd/2 5 | -------------------------------------------------------------------------------- /5/fpm/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.3-fpm 2 | 3 | # opencontainers annotations https://github.com/opencontainers/image-spec/blob/master/annotations.md 4 | LABEL org.opencontainers.image.authors="Alexis Saettler " \ 5 | org.opencontainers.image.title="MonicaHQ, the Personal Relationship Manager" \ 6 | org.opencontainers.image.description="This is MonicaHQ, your personal memory! MonicaHQ is like a CRM but for the friends, family, and acquaintances around you." \ 7 | org.opencontainers.image.url="https://monicahq.com" \ 8 | org.opencontainers.image.source="https://github.com/monicahq/docker" \ 9 | org.opencontainers.image.vendor="Monica" 10 | 11 | # entrypoint.sh dependencies 12 | RUN set -ex; \ 13 | \ 14 | apt-get update; \ 15 | apt-get install -y --no-install-recommends \ 16 | bash \ 17 | busybox-static \ 18 | ; \ 19 | rm -rf /var/lib/apt/lists/* 20 | 21 | # Install required PHP extensions 22 | RUN set -ex; \ 23 | \ 24 | savedAptMark="$(apt-mark showmanual)"; \ 25 | \ 26 | apt-get update; \ 27 | apt-get install -y --no-install-recommends \ 28 | libicu-dev \ 29 | zlib1g-dev \ 30 | libzip-dev \ 31 | libpng-dev \ 32 | libpq-dev \ 33 | libxml2-dev \ 34 | libfreetype6-dev \ 35 | libjpeg62-turbo-dev \ 36 | libgmp-dev \ 37 | libmemcached-dev \ 38 | libssl-dev \ 39 | libwebp-dev \ 40 | libcurl4-openssl-dev \ 41 | ; \ 42 | \ 43 | debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ 44 | if [ ! -e /usr/include/gmp.h ]; then ln -s /usr/include/$debMultiarch/gmp.h /usr/include/gmp.h; fi;\ 45 | docker-php-ext-configure intl; \ 46 | docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \ 47 | docker-php-ext-configure gmp; \ 48 | docker-php-ext-install -j$(nproc) \ 49 | intl \ 50 | zip \ 51 | bcmath \ 52 | gd \ 53 | gmp \ 54 | pdo_mysql \ 55 | mysqli \ 56 | pdo_pgsql \ 57 | soap \ 58 | ; \ 59 | \ 60 | # pecl will claim success even if one install fails, so we need to perform each install separately 61 | pecl install APCu-5.1.24; \ 62 | pecl install memcached-3.3.0; \ 63 | pecl install redis-6.2.0; \ 64 | \ 65 | docker-php-ext-enable \ 66 | apcu \ 67 | memcached \ 68 | redis \ 69 | ; \ 70 | \ 71 | # reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies 72 | apt-mark auto '.*' > /dev/null; \ 73 | apt-mark manual $savedAptMark; \ 74 | ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ 75 | | awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); print so }' \ 76 | | sort -u \ 77 | | xargs -r dpkg-query -S \ 78 | | cut -d: -f1 \ 79 | | sort -u \ 80 | | xargs -rt apt-mark manual; \ 81 | \ 82 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ 83 | rm -rf /var/lib/apt/lists/* 84 | 85 | # Set crontab for schedules 86 | RUN set -ex; \ 87 | \ 88 | mkdir -p /var/spool/cron/crontabs; \ 89 | rm -f /var/spool/cron/crontabs/root; \ 90 | echo '* * * * * php /var/www/html/artisan schedule:run -v' > /var/spool/cron/crontabs/www-data 91 | 92 | # Opcache 93 | ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \ 94 | PHP_OPCACHE_MAX_ACCELERATED_FILES="20000" \ 95 | PHP_OPCACHE_MEMORY_CONSUMPTION="192" \ 96 | PHP_OPCACHE_MAX_WASTED_PERCENTAGE="10" 97 | # Limits 98 | ENV PHP_MEMORY_LIMIT="512M" \ 99 | PHP_UPLOAD_LIMIT="512M" 100 | RUN set -ex; \ 101 | \ 102 | docker-php-ext-enable opcache; \ 103 | { \ 104 | echo '[opcache]'; \ 105 | echo 'opcache.enable=1'; \ 106 | echo 'opcache.revalidate_freq=0'; \ 107 | echo 'opcache.validate_timestamps=${PHP_OPCACHE_VALIDATE_TIMESTAMPS}'; \ 108 | echo 'opcache.max_accelerated_files=${PHP_OPCACHE_MAX_ACCELERATED_FILES}'; \ 109 | echo 'opcache.memory_consumption=${PHP_OPCACHE_MEMORY_CONSUMPTION}'; \ 110 | echo 'opcache.max_wasted_percentage=${PHP_OPCACHE_MAX_WASTED_PERCENTAGE}'; \ 111 | echo 'opcache.interned_strings_buffer=16'; \ 112 | echo 'opcache.fast_shutdown=1'; \ 113 | } > $PHP_INI_DIR/conf.d/opcache-recommended.ini; \ 114 | \ 115 | echo 'apc.enable_cli=1' >> $PHP_INI_DIR/conf.d/docker-php-ext-apcu.ini; \ 116 | \ 117 | { \ 118 | echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \ 119 | echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \ 120 | echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \ 121 | } > $PHP_INI_DIR/conf.d/limits.ini; 122 | 123 | 124 | 125 | WORKDIR /var/www/html 126 | 127 | # Define Monica version 128 | ENV MONICA_VERSION v5.0.0-beta.5 129 | LABEL org.opencontainers.image.revision="0c9a7dd1405f71fc46ea97f87b6c4ae67a423df3" \ 130 | org.opencontainers.image.version="v5.0.0-beta.5" 131 | 132 | RUN set -ex; \ 133 | fetchDeps=" \ 134 | gnupg \ 135 | dirmngr \ 136 | "; \ 137 | apt-get update; \ 138 | apt-get install -y --no-install-recommends $fetchDeps; \ 139 | \ 140 | for ext in tar.bz2 tar.bz2.asc; do \ 141 | curl -fsSL -o monica-${MONICA_VERSION}.$ext "https://github.com/monicahq/monica/releases/download/${MONICA_VERSION}/monica-${MONICA_VERSION}.$ext"; \ 142 | done; \ 143 | \ 144 | GPGKEY='BDAB0D0D36A00466A2964E85DE15667131EA6018'; \ 145 | export GNUPGHOME="$(mktemp -d)"; \ 146 | gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$GPGKEY"; \ 147 | gpg --batch --verify monica-${MONICA_VERSION}.tar.bz2.asc monica-${MONICA_VERSION}.tar.bz2; \ 148 | \ 149 | tar -xf monica-${MONICA_VERSION}.tar.bz2 -C /var/www/html --strip-components=1; \ 150 | \ 151 | gpgconf --kill all; \ 152 | rm -rf "$GNUPGHOME" monica-${MONICA_VERSION}.tar.bz2 monica-${MONICA_VERSION}.tar.bz2.asc; \ 153 | \ 154 | cp /var/www/html/.env.example /var/www/html/.env; \ 155 | chown -R www-data:www-data /var/www/html; \ 156 | \ 157 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps; \ 158 | rm -rf /var/lib/apt/lists/* 159 | 160 | COPY --chown=www-data:www-data env.production .env 161 | COPY entrypoint.sh \ 162 | queue.sh \ 163 | cron.sh \ 164 | /usr/local/bin/ 165 | 166 | ENTRYPOINT ["entrypoint.sh"] 167 | CMD ["php-fpm"] 168 | -------------------------------------------------------------------------------- /5/fpm/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec busybox crond -f -l 0 -L /proc/1/fd/1 5 | -------------------------------------------------------------------------------- /5/fpm/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -Eeo pipefail 4 | 5 | # set environment variables with docker secrets in /run/secrets/* 6 | supportedSecrets=( "DB_PASSWORD" 7 | "DATABASE_URL" 8 | "APP_KEY" 9 | "MAIL_PASSWORD" 10 | "REDIS_PASSWORD" 11 | "AWS_ACCESS_KEY_ID" 12 | "AWS_SECRET_ACCESS_KEY" 13 | "AWS_KEY" 14 | "AWS_SECRET" 15 | "LOCATION_IQ_API_KEY" 16 | "WEATHERAPI_KEY" 17 | "MAPBOX_API_KEY" 18 | ) 19 | 20 | for secret in "${supportedSecrets[@]}"; do 21 | envFile="${secret}_FILE" 22 | if [ -n "${!envFile}" ] && [ -f "${!envFile}" ]; then 23 | val="$(< "${!envFile}")" 24 | export "${secret}"="$val" 25 | echo "${secret} environment variable was set by secret ${envFile}" 26 | fi 27 | done 28 | 29 | if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ]; then 30 | 31 | MONICADIR=/var/www/html 32 | ARTISAN="php ${MONICADIR}/artisan" 33 | 34 | # Ensure storage directories are present 35 | STORAGE=${MONICADIR}/storage 36 | mkdir -p ${STORAGE}/logs 37 | mkdir -p ${STORAGE}/app/public 38 | mkdir -p ${STORAGE}/framework/views 39 | mkdir -p ${STORAGE}/framework/cache 40 | mkdir -p ${STORAGE}/framework/sessions 41 | chown -R www-data:www-data ${STORAGE} 42 | chmod -R g+rw ${STORAGE} 43 | 44 | if [ "${DB_CONNECTION:-sqlite}" == "sqlite" ]; then 45 | dbPath="${DB_DATABASE:-database/database.sqlite}" 46 | if [ ! -f "$dbPath" ]; then 47 | echo "Creating sqlite database at ${dbPath} — make sure it will be saved in a persistent volume." 48 | touch "$dbPath" 49 | chown www-data:www-data "$dbPath" 50 | fi 51 | fi 52 | 53 | if [ -z "${APP_KEY:-}" ]; then 54 | ${ARTISAN} key:generate --no-interaction 55 | key=$(grep APP_KEY .env | cut -c 9-) 56 | echo "APP_KEY generated: $key — save it for later usage." 57 | else 58 | echo "APP_KEY already set." 59 | fi 60 | 61 | # Run migrations 62 | ${ARTISAN} waitfordb 63 | ${ARTISAN} monica:setup --force -vv 64 | 65 | fi 66 | 67 | exec "$@" 68 | -------------------------------------------------------------------------------- /5/fpm/env.production: -------------------------------------------------------------------------------- 1 | APP_NAME=Monica 2 | APP_ENV=production 3 | APP_KEY= 4 | APP_DEBUG=false 5 | APP_URL=https://monica.test 6 | 7 | # Database to store information 8 | DB_CONNECTION=sqlite 9 | # DB_DATABASE=/var/www/html/storage/database.sqlite 10 | 11 | # Drivers 12 | CACHE_STORE=database 13 | QUEUE_CONNECTION=sync 14 | SESSION_DRIVER=database 15 | 16 | # Search 17 | SCOUT_DRIVER=database 18 | SCOUT_QUEUE=false 19 | 20 | # Log 21 | LOG_CHANNEL=stderr 22 | -------------------------------------------------------------------------------- /5/fpm/queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec php /var/www/html/artisan queue:work --sleep=10 --timeout=0 --tries=3 --queue=high,default,low >/proc/1/fd/1 2>/proc/1/fd/2 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | releases=( 5 | 4 6 | 5 7 | ) 8 | 9 | variants=( 10 | apache 11 | fpm 12 | fpm-alpine 13 | ) 14 | 15 | declare -A php_version=( 16 | [default]='8.2' 17 | [5]='8.2' 18 | [4]='8.1' 19 | ) 20 | 21 | nocache="--no-cache" 22 | if [ -n "${1:-}" ]; then 23 | releases=( "$1" ) 24 | fi 25 | if [ -n "${2:-}" ]; then 26 | variants=( "$2" ) 27 | nocache="" 28 | fi 29 | 30 | for release in ${releases[@]}; do 31 | for variant in ${variants[@]}; do 32 | php=${php_version[$release]-${php_version[default]}} 33 | docker pull php:$php-$variant 34 | docker build $nocache -t monica:$release-$variant $release/$variant 35 | done 36 | done 37 | 38 | docker images 39 | -------------------------------------------------------------------------------- /generate-stackbrew-library.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | self="$(basename "$BASH_SOURCE")" 5 | cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" 6 | defaultVariant='apache' 7 | 8 | # Get the most recent commit which modified any of "$@". 9 | fileCommit() { 10 | git log -1 --format='format:%H' HEAD -- "$@" 11 | } 12 | 13 | # Get the most recent commit which modified "$1/Dockerfile" or any file that 14 | # the Dockerfile copies into the rootfs (with COPY). 15 | dockerfileCommit() { 16 | local dir="$1"; shift 17 | ( 18 | cd "$dir"; 19 | fileCommit Dockerfile \ 20 | $(git show HEAD:./Dockerfile | awk ' 21 | toupper($1) == "COPY" { 22 | for (i = 2; i < NF; i++) 23 | print $i; 24 | } 25 | ') 26 | ) 27 | } 28 | 29 | getArches() { 30 | local repo="$1"; shift 31 | local officialImagesUrl='https://github.com/docker-library/official-images/raw/master/library/' 32 | 33 | eval "declare -g -A parentRepoToArches=( $( 34 | find -maxdepth 3 -name 'Dockerfile' -exec awk ' 35 | toupper($1) == "FROM" && $2 !~ /^('"$repo"'|scratch|microsoft\/[^:]+)(:|$)/ { 36 | print "'"$officialImagesUrl"'" $2 37 | } 38 | ' '{}' + \ 39 | | sort -u \ 40 | | xargs ./bashbrew cat --format '[{{ .RepoName }}:{{ .TagName }}]="{{ join " " .TagEntry.Architectures }}"' 41 | ) )" 42 | } 43 | getArches 'monica' 44 | 45 | # Header. 46 | cat <<-EOH 47 | # This file is generated via https://github.com/monicahq/docker/blob/$(fileCommit "$self")/$self 48 | Maintainers: Alexis Saettler (@asbiin) 49 | GitRepo: https://github.com/monicahq/docker.git 50 | GitFetch: refs/heads/main 51 | EOH 52 | 53 | # prints "$2$1$3$1...$N" 54 | join() { 55 | local sep="$1"; shift 56 | local out; printf -v out "${sep//%/%%}%s" "$@" 57 | echo "${out#$sep}" 58 | } 59 | 60 | SEARCHFOR="Upgrade available - the latest version is " 61 | latest="$(curl -fsSL 'https://api.github.com/repos/monicahq/monica/releases/latest' | jq -r '.tag_name' | cut -c 2-)" 62 | 63 | # releases=( */ ) 64 | # releases=( "${releases[@]%/}" ) 65 | releases=( 4 5 ) 66 | 67 | for release in "${releases[@]}"; do 68 | 69 | pushd "$release" > /dev/null 70 | 71 | variants=( */ ) 72 | variants=( "${variants[@]%/}" ) 73 | 74 | for variant in "${variants[@]}"; do 75 | commit="$(dockerfileCommit "$variant")" 76 | fullversion="$(cat "$variant/Dockerfile" | grep -iF "ENV MONICA_VERSION" | sed -E "s@ENV MONICA_VERSION v([0-9.]+)@\1@")" 77 | 78 | versionAliases=( "$fullversion" "${fullversion%.*}" "${fullversion%.*.*}" ) 79 | if [ "$fullversion" = "$latest" ]; then 80 | versionAliases+=( "latest" ) 81 | fi 82 | 83 | variantAliases=( "${versionAliases[@]/%/-$variant}" ) 84 | variantAliases=( "${variantAliases[@]//latest-}" ) 85 | 86 | if [ "$fullversion" = "$latest" -a "$variant" = "$defaultVariant" ]; then 87 | variantAliases+=( "${versionAliases[@]}" ) 88 | fi 89 | 90 | variantParent="$(awk 'toupper($1) == "FROM" { print $2 }' "$variant/Dockerfile")" 91 | variantArches="${parentRepoToArches[$variantParent]}" 92 | 93 | cat <<-EOE 94 | 95 | Tags: $(join ', ' "${variantAliases[@]}") 96 | Architectures: $(join ', ' $variantArches) 97 | Directory: $release/$variant 98 | GitCommit: $commit 99 | EOE 100 | done 101 | 102 | popd > /dev/null 103 | 104 | done -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | IFS=' 5 | ' 6 | 7 | _template() { 8 | sed -e 's/\\/\\\\/g' $1 | sed -E ':a;N;$!ba;s/\r{0,1}\n/%0A/g' 9 | } 10 | 11 | releases=( 12 | 4 13 | 5 14 | ) 15 | 16 | variants=( 17 | apache 18 | fpm 19 | fpm-alpine 20 | ) 21 | 22 | declare -A php_version=( 23 | [default]='8.3' 24 | [5]='8.3' 25 | [4]='8.2' 26 | ) 27 | 28 | declare -A cmd=( 29 | [apache]='apache2-foreground' 30 | [fpm]='php-fpm' 31 | [fpm-alpine]='php-fpm' 32 | ) 33 | 34 | declare -A base=( 35 | [apache]='debian' 36 | [fpm]='debian' 37 | [fpm-alpine]='alpine' 38 | ) 39 | 40 | declare -A document=( 41 | [apache]=$(_template .templates/Dockerfile-apache.template) 42 | [fpm]='' 43 | [fpm-alpine]='' 44 | ) 45 | 46 | label=$(_template .templates/Dockerfile-label.template) 47 | 48 | echo Initialisation 49 | 50 | apcu_version="$( 51 | git ls-remote --tags https://github.com/krakjoe/apcu.git \ 52 | | cut -d/ -f3 \ 53 | | grep -viE -- 'rc|b' \ 54 | | sed -E 's/^v//' \ 55 | | sort -V \ 56 | | tail -1 57 | )" 58 | echo " APCu version: $apcu_version" 59 | 60 | memcached_version="$( 61 | git ls-remote --tags https://github.com/php-memcached-dev/php-memcached.git \ 62 | | cut -d/ -f3 \ 63 | | grep -viE -- 'rc|b' \ 64 | | sed -E 's/^[rv]//' \ 65 | | sort -V \ 66 | | tail -1 67 | )" 68 | echo " Memcached version: $memcached_version" 69 | 70 | redis_version="$( 71 | git ls-remote --tags https://github.com/phpredis/phpredis.git \ 72 | | cut -d/ -f3 \ 73 | | grep -viE '[a-z]' \ 74 | | tr -d '^{}' \ 75 | | sort -V \ 76 | | tail -1 77 | )" 78 | echo " Redis version: $redis_version" 79 | 80 | declare -A pecl_versions=( 81 | [APCu]="$apcu_version" 82 | [memcached]="$memcached_version" 83 | [redis]="$redis_version" 84 | ) 85 | 86 | _githubapi() { 87 | if [ -n "${GITHUB_TOKEN:-}" ]; then 88 | curl -fsSL -H "Authorization: token $GITHUB_TOKEN" $1; 89 | else 90 | curl -fsSL $1; 91 | fi 92 | } 93 | 94 | head=$(_template .templates/Dockerfile-head.template) 95 | extra=$(_template .templates/Dockerfile-extra.template) 96 | install=$(_template .templates/Dockerfile-install.template) 97 | 98 | if [ -n "${1:-}" ]; then 99 | releases=( "$1" ) 100 | fi 101 | if [ -n "${2:-}" ]; then 102 | variants=( "$2" ) 103 | fi 104 | 105 | for release in "${releases[@]}"; do 106 | 107 | echo "Processing release $release" 108 | 109 | version="$(_githubapi 'https://api.github.com/repos/monicahq/monica/releases' | jq -r 'map(select(.tag_name | startswith ("v'$release'"))) | .[0].tag_name')" 110 | 111 | echo " Monica version: $version" 112 | commit="$(_githubapi 'https://api.github.com/repos/monicahq/monica/tags' | jq -r 'map(select(.name | contains ("'$version'"))) | .[].commit.sha')" 113 | echo " Commit: $commit" 114 | 115 | foot=$(_template .templates/Dockerfile-foot$release.template) 116 | 117 | for variant in "${variants[@]}"; do 118 | echo Generating $variant variant... 119 | rm -rf $release/$variant 120 | mkdir -p $release/$variant 121 | phpVersion=${php_version[$release]-${php_version[default]}} 122 | 123 | template=".templates/Dockerfile-${base[$variant]}.template" 124 | 125 | sed -e ' 126 | s@%%HEAD%%@'"$head"'@; 127 | s@%%FOOT%%@'"$foot"'@; 128 | s@%%EXTRA_INSTALL%%@'"$extra"'@; 129 | s@%%INSTALL%%@'"$install"'@; 130 | s/%%VARIANT%%/'"$variant"'/; 131 | s/%%PHP_VERSION%%/'"$phpVersion"'/; 132 | s#%%LABEL%%#'"$label"'#; 133 | s/%%VERSION%%/'"$version"'/g; 134 | s/%%COMMIT%%/'"$commit"'/; 135 | s/%%CMD%%/'"${cmd[$variant]}"'/; 136 | s@%%APACHE_DOCUMENT%%@'"${document[$variant]}"'@; 137 | s/%%APCU_VERSION%%/'"${pecl_versions[APCu]}"'/; 138 | s/%%MEMCACHED_VERSION%%/'"${pecl_versions[memcached]}"'/; 139 | s/%%REDIS_VERSION%%/'"${pecl_versions[redis]}"'/; 140 | ' \ 141 | -e "s/%0A/\n/g;" \ 142 | $template > "$release/$variant/Dockerfile" 143 | 144 | cp .templates/scripts/$release/* $release/$variant/ 145 | done 146 | done 147 | --------------------------------------------------------------------------------