├── config ├── nginx │ ├── rewrite │ │ └── project.conf │ ├── d4d │ │ ├── sf.conf.default │ │ └── cache.conf │ ├── nginx.conf │ ├── project.conf.default │ ├── project-ssl.conf.default │ └── Dockerfile.build ├── php │ ├── php-fpm.d │ │ ├── zz-docker.conf │ │ └── www.conf │ ├── conf.d │ │ └── xdebug.d4d │ └── Dockerfile.build ├── phpmyadmin │ ├── config.user.inc.php.d4d │ └── Dockerfile.build ├── supervisor │ └── conf.d │ │ └── messenger-worker.conf ├── mysql │ └── d4d.cnf.d4d └── mongodb │ └── mongod.conf ├── user ├── .gitignore ├── .gitconfig ├── .bashrc ├── mysql │ └── initdb.d │ │ └── 01.sql ├── mongodb │ └── initdb.d │ │ └── create-app-user.sh └── bash_completion │ └── console ├── docker ├── network.yml ├── redis.yml ├── mailhog.yml ├── mailpit.yml ├── env │ └── php.yml ├── rabbitmq.yml ├── ngrok.yml ├── phpmyadmin.yml ├── mongodb.yml ├── elk.yml ├── mariadb.yml ├── mysql.yml ├── compose.yml ├── elasticsearch.yml └── php.yml ├── support ├── blackfire_io.png └── directadmin.png ├── scripts ├── check_php_extensions.sh └── mysql_dump.sh ├── .github ├── workflows │ ├── qodana_code_quality.yml │ └── releaser.yaml └── FUNDING.yml ├── .env.secret.dist ├── .gitignore ├── go.mod ├── LICENSE ├── commands ├── self_update.go ├── password_show.go ├── root.go └── start.go ├── qodana.yaml ├── main.go ├── .goreleaser.yaml ├── .env.dist ├── util └── util.go ├── go.sum ├── README.md └── d4d /config/nginx/rewrite/project.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /user/.gitignore: -------------------------------------------------------------------------------- 1 | # IDEs 2 | /.idea 3 | 4 | # System files 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /user/.gitconfig: -------------------------------------------------------------------------------- 1 | [core] 2 | autocrlf = input 3 | excludesfile = /var/www/.gitignore 4 | -------------------------------------------------------------------------------- /docker/network.yml: -------------------------------------------------------------------------------- 1 | 2 | networks: 3 | default: 4 | external: 5 | name: external-d4d -------------------------------------------------------------------------------- /config/php/php-fpm.d/zz-docker.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | daemonize = no 3 | 4 | [www] 5 | listen = 9000 6 | -------------------------------------------------------------------------------- /support/blackfire_io.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StaffNowa/docker-symfony/HEAD/support/blackfire_io.png -------------------------------------------------------------------------------- /support/directadmin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StaffNowa/docker-symfony/HEAD/support/directadmin.png -------------------------------------------------------------------------------- /user/.bashrc: -------------------------------------------------------------------------------- 1 | if [ -f /etc/bash_completion ] && ! shopt -oq posix; then 2 | . /etc/bash_completion 3 | fi -------------------------------------------------------------------------------- /docker/redis.yml: -------------------------------------------------------------------------------- 1 | 2 | redis: 3 | image: redis:latest 4 | environment: 5 | TZ: ${DEFAULT_TIMEZONE} 6 | -------------------------------------------------------------------------------- /user/mysql/initdb.d/01.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS `db_name_test`; 2 | GRANT ALL ON `db_name_test`.* TO 'db_user'@'%'; -------------------------------------------------------------------------------- /docker/mailhog.yml: -------------------------------------------------------------------------------- 1 | 2 | mailhog: 3 | image: mailhog/mailhog 4 | ports: 5 | - "${PORT_MAIL_SMTP}:1025" 6 | - "${PORT_MAIL_HTTP}:8025" 7 | -------------------------------------------------------------------------------- /docker/mailpit.yml: -------------------------------------------------------------------------------- 1 | 2 | mailpit: 3 | image: axllent/mailpit 4 | ports: 5 | - "${PORT_MAIL_SMTP}:1025" 6 | - "${PORT_MAIL_HTTP}:8025" 7 | -------------------------------------------------------------------------------- /docker/env/php.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | - DATABASE_URL=mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@mysql:3306/${MYSQL_DATABASE} 3 | - MESSENGER_TRANSPORT_DSN=amqp://guest:guest@rabbitmq:5672/%2f/messages 4 | -------------------------------------------------------------------------------- /docker/rabbitmq.yml: -------------------------------------------------------------------------------- 1 | 2 | rabbitmq: 3 | image: rabbitmq:${RABBITMQ_VERSION}-management 4 | ports: 5 | - 5672:5672 6 | - ${PORT_RABBITMQ_TCP_LISTENER}:5673 7 | - ${PORT_RABBITMQ_MANAGEMENT}:15672 8 | -------------------------------------------------------------------------------- /config/nginx/d4d/sf.conf.default: -------------------------------------------------------------------------------- 1 | location / { 2 | index __SYMFONY_FRONT_CONTROLLER__; 3 | try_files $uri @rewriteapp; 4 | } 5 | 6 | location @rewriteapp { 7 | rewrite ^(.*)$ /__SYMFONY_FRONT_CONTROLLER__/$1 last; 8 | } -------------------------------------------------------------------------------- /config/phpmyadmin/config.user.inc.php.d4d: -------------------------------------------------------------------------------- 1 | "${BACKUP_DIR}/backup_"$db"_$(date +%Y%m%d_%H%M%S).sql.gz"; done 20 | chown 1000:1000 -R ${BACKUP_MAIN_DIR} 21 | -------------------------------------------------------------------------------- /docker/elk.yml: -------------------------------------------------------------------------------- 1 | 2 | elasticsearch: 3 | image: docker.elastic.co/elasticsearch/elasticsearch:${ELK_VERSION} 4 | environment: 5 | ES_JAVA_OPTS: "-Xmx256m -Xms256m" 6 | discovery.type: single-node 7 | ports: 8 | - "${PORT_ELASTICSEARCH}:9200" 9 | - "9300:9300" 10 | 11 | logstash: 12 | image: docker.elastic.co/logstash/logstash:${ELK_VERSION} 13 | depends_on: 14 | - elasticsearch 15 | environment: 16 | LS_JAVA_OPTS: "-Xmx256m -Xms256m" 17 | 18 | kibana: 19 | image: docker.elastic.co/kibana/kibana:${ELK_VERSION} 20 | depends_on: 21 | - elasticsearch 22 | ports: 23 | - "${PORT_ELASTICSEARCH_KIBANA}:5601" -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://paypal.me/staffnowa'] 13 | -------------------------------------------------------------------------------- /config/mongodb/mongod.conf: -------------------------------------------------------------------------------- 1 | # mongod.conf 2 | 3 | # for documentation of all options, see: 4 | # http://docs.mongodb.org/manual/reference/configuration-options/ 5 | 6 | # Where and how to store data. 7 | storage: 8 | dbPath: /var/lib/mongodb 9 | journal: 10 | enabled: true 11 | # engine: 12 | # mmapv1: 13 | # wiredTiger: 14 | 15 | # where to write logging data. 16 | systemLog: 17 | destination: file 18 | logAppend: true 19 | path: /var/log/mongodb/mongod.log 20 | 21 | # network interfaces 22 | net: 23 | port: 27017 24 | bindIp: 127.0.0.1 25 | 26 | 27 | # how the process runs 28 | processManagement: 29 | timeZoneInfo: /usr/share/zoneinfo 30 | 31 | #security: 32 | 33 | #operationProfiling: 34 | 35 | #replication: 36 | 37 | #sharding: 38 | 39 | ## Enterprise-Only Options: 40 | 41 | #auditLog: 42 | 43 | #snmp: 44 | -------------------------------------------------------------------------------- /docker/mariadb.yml: -------------------------------------------------------------------------------- 1 | 2 | mysql: 3 | image: mariadb:${MARIADB_VERSION} 4 | environment: 5 | MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} 6 | MYSQL_DATABASE: ${MYSQL_DATABASE} 7 | MYSQL_USER: ${MYSQL_USER} 8 | MYSQL_PASSWORD: ${MYSQL_PASSWORD} 9 | TZ: ${DEFAULT_TIMEZONE} 10 | ports: 11 | - ${PORT_MYSQL}:3306 12 | volumes: 13 | - ${MYSQL_DATA_PATH}:/var/lib/mysql:cached 14 | - ${MYSQL_DUMP_PATH}:/tmp/db 15 | - ${USER_CONFIG_PATH}/.my.cnf:/root/.my.cnf:ro 16 | - ./scripts/mysql_dump.sh:/tmp/db/mysql_dump.sh:ro 17 | - ./config/mysql/d4d.cnf:/etc/mysql/conf.d/d4d.cnf:ro 18 | - ${USER_CONFIG_PATH}/mysql/initdb.d:/docker-entrypoint-initdb.d 19 | command: [ 20 | "--character-set-server=${MYSQL_CHARACTER_SET_SERVER}", 21 | "--collation-server=${MYSQL_COLLATION_SERVER}" 22 | ] 23 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module docker-symfony 2 | 3 | go 1.23.4 4 | 5 | require ( 6 | github.com/joho/godotenv v1.5.1 7 | github.com/sethvargo/go-password v0.3.1 8 | github.com/symfony-cli/console v1.1.5 9 | github.com/symfony-cli/terminal v1.0.7 10 | golang.org/x/crypto v0.31.0 11 | ) 12 | 13 | require ( 14 | github.com/agext/levenshtein v1.2.3 // indirect 15 | github.com/hashicorp/errwrap v1.1.0 // indirect 16 | github.com/hashicorp/go-multierror v1.1.1 // indirect 17 | github.com/mattn/go-colorable v0.1.13 // indirect 18 | github.com/mattn/go-isatty v0.0.20 // indirect 19 | github.com/mitchellh/go-homedir v1.1.0 // indirect 20 | github.com/pkg/errors v0.9.1 // indirect 21 | github.com/posener/complete v1.2.3 // indirect 22 | github.com/rs/zerolog v1.33.0 // indirect 23 | golang.org/x/sys v0.28.0 // indirect 24 | golang.org/x/term v0.27.0 // indirect 25 | gopkg.in/yaml.v3 v3.0.1 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /docker/mysql.yml: -------------------------------------------------------------------------------- 1 | 2 | mysql: 3 | image: mysql:${MYSQL_VERSION} 4 | environment: 5 | MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} 6 | MYSQL_DATABASE: ${MYSQL_DATABASE} 7 | MYSQL_USER: ${MYSQL_USER} 8 | MYSQL_PASSWORD: ${MYSQL_PASSWORD} 9 | TZ: ${DEFAULT_TIMEZONE} 10 | ports: 11 | - ${PORT_MYSQL}:3306 12 | volumes: 13 | - ${MYSQL_DATA_PATH}:/var/lib/mysql:cached 14 | - ${MYSQL_DUMP_PATH}:/tmp/db 15 | - ${USER_CONFIG_PATH}/.my.cnf:/root/.my.cnf:ro 16 | - ./scripts/mysql_dump.sh:/tmp/db/mysql_dump.sh:ro 17 | - ./config/mysql/d4d.cnf:/etc/mysql/mysql.conf.d/d4d.cnf:ro 18 | - ${USER_CONFIG_PATH}/mysql/initdb.d:/docker-entrypoint-initdb.d 19 | command: [ 20 | '--character-set-server=${MYSQL_CHARACTER_SET_SERVER}', 21 | '--collation-server=${MYSQL_COLLATION_SERVER}', 22 | '--default-authentication-plugin=mysql_native_password' 23 | ] 24 | -------------------------------------------------------------------------------- /docker/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | nginx: 3 | build: 4 | context: config/nginx 5 | args: 6 | PROJECT_DOMAIN_1: ${PROJECT_DOMAIN_1} 7 | PROJECT_DOMAIN_2: ${PROJECT_DOMAIN_2} 8 | PROJECT_DOMAIN_3: ${PROJECT_DOMAIN_3} 9 | PROJECT_DOMAIN_4: ${PROJECT_DOMAIN_4} 10 | DOCUMENT_ROOT: ${DOCUMENT_ROOT} 11 | DEBIAN_VERSION: ${DEBIAN_VERSION} 12 | SYMFONY_FRONT_CONTROLLER: ${SYMFONY_FRONT_CONTROLLER} 13 | PHP_MAX_EXECUTION_TIME: ${PHP_MAX_EXECUTION_TIME} 14 | PHP_UPLOAD_MAX_FILESIZE: ${PHP_UPLOAD_MAX_FILESIZE} 15 | PORT_PHP: ${PORT_PHP} 16 | ports: 17 | - ${PORT_NGINX}:80 18 | - ${PORT_NGINX_SSL}:443 19 | __NGINX_NETWORKS__ 20 | volumes: 21 | - ${PROJECT_PATH}:/var/www/project:cached 22 | - ${NGINX_LOG_PATH}:/var/log/nginx 23 | - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro 24 | depends_on: 25 | - php 26 | environment: 27 | - TZ=${DEFAULT_TIMEZONE} 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright PRADO.LT 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /commands/self_update.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "docker-symfony/util" 5 | "fmt" 6 | "github.com/symfony-cli/console" 7 | "github.com/symfony-cli/terminal" 8 | "runtime" 9 | ) 10 | 11 | var selfUpdateCmd = &console.Command{ 12 | Category: "d4d", 13 | Name: "self-update", 14 | Aliases: []*console.Alias{{Name: "self-update"}}, 15 | Usage: "", 16 | Action: func(c *console.Context) error { 17 | os := runtime.GOOS 18 | arch := runtime.GOARCH 19 | 20 | util.ExecCommand("clear") 21 | terminal.Println("We will process upgrading Docker for Symfony to the latest version.") 22 | 23 | var filename = "" 24 | if os != "darwin" { 25 | filename = fmt.Sprintf("d4d_linux_%s.tar.gz", arch) 26 | } else { 27 | filename = "d4d_darwin_all.tar.gz" 28 | } 29 | 30 | util.DownloadFile(filename, "https://github.com/StaffNowa/docker-symfony/releases/latest/download/"+filename) 31 | util.ExecCommand("tar xzfv " + filename) 32 | terminal.Println("Docker for Symfony successfully upgraded to the latest version.") 33 | 34 | return nil 35 | }, 36 | } 37 | -------------------------------------------------------------------------------- /config/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes auto; 3 | pid /run/nginx.pid; 4 | 5 | events { 6 | worker_connections 2048; 7 | multi_accept on; 8 | use epoll; 9 | } 10 | 11 | http { 12 | server_tokens off; 13 | sendfile on; 14 | tcp_nopush on; 15 | tcp_nodelay on; 16 | keepalive_timeout 15; 17 | types_hash_max_size 2048; 18 | include /etc/nginx/mime.types; 19 | default_type application/octet-stream; 20 | access_log off; 21 | error_log off; 22 | gzip on; 23 | gzip_disable "msie6"; 24 | 25 | gzip_comp_level 6; 26 | gzip_min_length 1100; 27 | gzip_buffers 16 8k; 28 | gzip_proxied any; 29 | gzip_types 30 | text/plain 31 | text/css 32 | text/js 33 | text/xml 34 | text/javascript 35 | application/javascript 36 | application/json 37 | application/xml 38 | application/rss+xml 39 | image/svg+xml; 40 | 41 | include /etc/nginx/conf.d/*.conf; 42 | include /etc/nginx/sites-enabled/*; 43 | open_file_cache max=100; 44 | } -------------------------------------------------------------------------------- /qodana.yaml: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------------------# 2 | # Qodana analysis is configured by qodana.yaml file # 3 | # https://www.jetbrains.com/help/qodana/qodana-yaml.html # 4 | #-------------------------------------------------------------------------------# 5 | version: "1.0" 6 | 7 | #Specify inspection profile for code analysis 8 | profile: 9 | name: qodana.starter 10 | 11 | #Enable inspections 12 | #include: 13 | # - name: 14 | 15 | #Disable inspections 16 | #exclude: 17 | # - name: 18 | # paths: 19 | # - 20 | 21 | #Execute shell command before Qodana execution (Applied in CI/CD pipeline) 22 | #bootstrap: sh ./prepare-qodana.sh 23 | 24 | #Install IDE plugins before Qodana execution (Applied in CI/CD pipeline) 25 | #plugins: 26 | # - id: #(plugin id can be found at https://plugins.jetbrains.com) 27 | 28 | #Specify Qodana linter for analysis (Applied in CI/CD pipeline) 29 | linter: jetbrains/qodana-go:latest 30 | -------------------------------------------------------------------------------- /config/phpmyadmin/Dockerfile.build: -------------------------------------------------------------------------------- 1 | FROM __PHP_MY_ADMIN__ 2 | 3 | LABEL maintainer="Vasilij Dusko " 4 | 5 | ARG PHP_MEMORY_LIMIT 6 | ARG PHP_UPLOAD_MAX_FILESIZE 7 | ARG DEFAULT_TIMEZONE 8 | ARG PHP_MAX_EXECUTION_TIME 9 | 10 | RUN printf 'memory_limit = %s\n' ${PHP_MEMORY_LIMIT} >> $PHP_INI_DIR/conf.d/phpmyadmin-misc.ini && \ 11 | sed -i 's#${MAX_EXECUTION_TIME}#'"${PHP_MAX_EXECUTION_TIME}"'#g' $PHP_INI_DIR/conf.d/phpmyadmin-misc.ini && \ 12 | sed -i 's#${MEMORY_LIMIT}#'"${PHP_MEMORY_LIMIT}"'#g' $PHP_INI_DIR/conf.d/phpmyadmin-misc.ini && \ 13 | sed -i 's#${UPLOAD_LIMIT}#'"${PHP_UPLOAD_MAX_FILESIZE}"'#g' $PHP_INI_DIR/conf.d/phpmyadmin-misc.ini && \ 14 | printf 'post_max_size = %s\n' ${PHP_UPLOAD_MAX_FILESIZE} >> $PHP_INI_DIR/conf.d/phpmyadmin-custom.ini && \ 15 | printf 'upload_max_filesize = %s\n' ${PHP_UPLOAD_MAX_FILESIZE} >> $PHP_INI_DIR/conf.d/phpmyadmin-custom.ini && \ 16 | printf 'session.gc_maxlifetime = %s\n' 86400 >> $PHP_INI_DIR/conf.d/phpmyadmin-custom.ini && \ 17 | printf '[PHP]\ndate.timezone = "%s"\n' ${DEFAULT_TIMEZONE} > $PHP_INI_DIR/conf.d/tzone.ini && \ 18 | echo '.nav-item,.navbar-collapse{background: #1bb1dc !important}' >> /var/www/html/themes/pmahomme/css/theme.css -------------------------------------------------------------------------------- /config/nginx/project.conf.default: -------------------------------------------------------------------------------- 1 | server { 2 | server_name 3 | __PROJECT_DOMAIN_1__ 4 | __PROJECT_DOMAIN_2__ 5 | __PROJECT_DOMAIN_3__ 6 | __PROJECT_DOMAIN_4__ 7 | ; 8 | root /var/www/project/__DOCUMENT_ROOT__; 9 | 10 | include /etc/nginx/rewrite/project.conf; 11 | 12 | access_log /var/log/nginx/project_access.log; 13 | error_log /var/log/nginx/project_error.log; 14 | 15 | # strip app.php/ prefix if it is present 16 | rewrite ^/app\.php/?(.*)$ /$1 permanent; 17 | 18 | include __INCLUDE__; 19 | 20 | __INCLUDE_CACHE__ 21 | 22 | # pass the PHP script to FastCGI server from upstream phpfcgi 23 | location ~ ^/(app|app_dev|index|config|_intellij_phpdebug_validator)\.php(/|$) { 24 | fastcgi_pass php-upstream; 25 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 26 | include fastcgi_params; 27 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 28 | fastcgi_param SYMFONY_ENV dev; 29 | fastcgi_param HTTPS off; 30 | fastcgi_read_timeout __PHP_MAX_EXECUTION_TIME__; 31 | 32 | fastcgi_buffers __NGINX_FASTCGI_BUFFERS__; 33 | fastcgi_buffer_size __NGINX_FASTCGI_BUFFER_SIZE__; 34 | } 35 | 36 | client_max_body_size __PHP_UPLOAD_MAX_FILESIZE__; 37 | } -------------------------------------------------------------------------------- /docker/elasticsearch.yml: -------------------------------------------------------------------------------- 1 | 2 | # elasticsearch server (official image) 3 | # https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html 4 | elasticsearch: 5 | container_name: elasticsearch 6 | image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTICSEARCH_VERSION} 7 | ports: 8 | - ${PORT_ELASTICSEARCH}:9200 9 | environment: 10 | - "discovery.type=single-node" 11 | - "bootstrap.memory_lock=true" 12 | - "ES_JAVA_OPTS=-Xms1G -Xmx1G" 13 | - "xpack.security.enabled=false" 14 | - "http.cors.enabled=true" 15 | - "http.cors.allow-origin=*" 16 | # elasticsearch head manager (fork of mobz/elasticsearch-head for elasticsearch 6) 17 | # /!\ it isn't an official image /!\ 18 | # https://hub.docker.com/r/tobias74/elasticsearch-head 19 | 20 | elasticsearch-head: 21 | container_name: elasticsearch-head 22 | depends_on: 23 | - elasticsearch 24 | image: tobias74/elasticsearch-head:6 25 | ports: 26 | - ${PORT_ELASTICSEARCH_HEAD}:9100 27 | 28 | kibana: 29 | container_name: kibana 30 | image: docker.elastic.co/kibana/kibana:6.8.6 31 | ports: 32 | - ${PORT_ELASTICSEARCH_KIBANA}:5601 33 | environment: 34 | - "ELASTICSEARCH_URL=http://elasticsearch" 35 | depends_on: 36 | - elasticsearch 37 | -------------------------------------------------------------------------------- /user/mongodb/initdb.d/create-app-user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # https://www.stuartellis.name/articles/shell-scripting/#enabling-better-error-handling-with-set 3 | set -Eeuo pipefail 4 | 5 | # Based on mongo/docker-entrypoint.sh 6 | # https://github.com/docker-library/mongo/blob/master/docker-entrypoint.sh#L303 7 | if [ "${MONGODB_USERNAME}" ] && [ "${MONGODB_PASSWORD}" ]; then 8 | rootAuthDatabase='admin' 9 | 10 | "${mongo[@]}" -u "${MONGODB_ROOT_USERNAME}" -p "${MONGODB_ROOT_PASSWORD}" --authenticationDatabase "$rootAuthDatabase" "${MONGODB_DATABASE}" <<-EOJS 11 | db.createUser({ 12 | user: $(_js_escape "$MONGODB_USERNAME"), 13 | pwd: $(_js_escape "$MONGODB_PASSWORD"), 14 | roles: [ { role: 'root', db: $(_js_escape "$rootAuthDatabase") } ] 15 | }) 16 | EOJS 17 | 18 | printf " +%-55s+\n" "-----------------------------------------------------------" 19 | printf " | %-55s %-2s|\n" "MongoDB root username: ${MONGODB_ROOT_USERNAME}" 20 | printf " | %-55s %-2s|\n" "MongoDB root password: ${MONGODB_ROOT_PASSWORD}" 21 | printf " +%-55s+\n" "-----------------------------------------------------------" 22 | printf " | %-55s %-2s|\n" "MongoDB database name: ${MONGODB_DATABASE}" 23 | printf " | %-55s %-2s|\n" "MongoDB username: ${MONGODB_USERNAME}" 24 | printf " | %-55s %-2s|\n" "MongoDB password: ${MONGODB_PASSWORD}" 25 | printf " +%-55s+\n" "-----------------------------------------------------------" 26 | fi -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "docker-symfony/commands" 5 | "docker-symfony/util" 6 | "fmt" 7 | "github.com/symfony-cli/console" 8 | "os" 9 | "time" 10 | ) 11 | 12 | var ( 13 | version = "dev" 14 | channel = "dev" 15 | buildDate string 16 | ) 17 | 18 | func Init() { 19 | currentDir := util.GetCurrentDir() 20 | 21 | // Added for security 22 | util.Chmod(currentDir+"/docker", 0700) 23 | util.Chmod(currentDir, 0700) 24 | 25 | env := currentDir + "/.env" 26 | envDist := env + ".dist" 27 | 28 | envSecret := env + ".secret" 29 | envSecretDist := envSecret + ".dist" 30 | 31 | if !util.FileExists(env) { 32 | util.Copy(envDist, env) 33 | } 34 | 35 | if !util.FileExists(envSecret) { 36 | util.Copy(envSecretDist, envSecret) 37 | } 38 | } 39 | 40 | func main() { 41 | Init() 42 | 43 | args := os.Args 44 | 45 | cmds := commands.CommonCommands() 46 | app := &console.Application{ 47 | Name: "D4D", 48 | Usage: "Docker Symfony gives you everything you need to develop a Symfony application. This complete stack runs with docker and docker-compose.", 49 | Copyright: fmt.Sprintf("(c) 2018-%d D4D", time.Now().Year()), 50 | Commands: cmds, 51 | Action: func(ctx *console.Context) error { 52 | if ctx.Args().Len() == 0 { 53 | return commands.WelcomeAction(ctx) 54 | } 55 | return console.ShowAppHelpAction(ctx) 56 | }, 57 | Before: commands.InitAppFunc, 58 | Version: version, 59 | Channel: channel, 60 | BuildDate: buildDate, 61 | } 62 | app.Run(args) 63 | } 64 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | project_name: d4d 2 | 3 | before: 4 | hooks: 5 | - go mod download 6 | 7 | changelog: 8 | sort: desc 9 | use: github 10 | filters: 11 | exclude: 12 | - Merge branch 13 | - Merge pull request 14 | 15 | builds: 16 | - env: 17 | - CGO_ENABLED=0 18 | goos: 19 | - linux 20 | - windows 21 | - darwin 22 | goarch: 23 | - 386 24 | - amd64 25 | - arm64 26 | ignore: 27 | - goos: windows 28 | goarch: arm64 29 | - goos: darwin 30 | goarch: 386 31 | main: ./ 32 | binary: main 33 | ldflags: -s -w -X 'main.channel={{ if index .Env "AUTOUPDATE_CHANNEL" }}{{ .Env.AUTOUPDATE_CHANNEL }}{{ else }}dev{{ end }}' -X 'main.buildDate={{ .Date }}' -X 'main.version={{ .Version }}' 34 | flags: 35 | - -trimpath 36 | 37 | archives: 38 | - name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' 39 | format_overrides: 40 | - goos: windows 41 | format: zip 42 | files: 43 | - config/* 44 | - docker/* 45 | - scripts/* 46 | - user/* 47 | - .env.dist 48 | - .env.secret.dist 49 | - .gitignore 50 | - LICENSE 51 | - README.md 52 | - d4d 53 | 54 | checksum: 55 | name_template: 'checksums.txt' 56 | 57 | snapshot: 58 | name_template: "next" 59 | 60 | universal_binaries: 61 | - replace: true 62 | name_template: main 63 | 64 | release: 65 | footer: | 66 | **Full Changelog**: https://github.com/StaffNowa/docker-symfony/compare/{{ .PreviousTag }}...{{ .Tag }} -------------------------------------------------------------------------------- /commands/password_show.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "docker-symfony/util" 5 | "fmt" 6 | "github.com/symfony-cli/console" 7 | "github.com/symfony-cli/terminal" 8 | "os" 9 | ) 10 | 11 | var passwordShowCmd = &console.Command{ 12 | Category: "d4d", 13 | Name: "passwd:show", 14 | Usage: "", 15 | Action: func(c *console.Context) error { 16 | doPasswordShow() 17 | 18 | return nil 19 | }, 20 | } 21 | 22 | func doPasswordShow() { 23 | util.ExecCommand("clear") 24 | 25 | util.LoadEnvFile(envFile) 26 | 27 | terminal.Println("") 28 | terminal.Println("The following information has been set:") 29 | terminal.Println("") 30 | terminal.Println("Server IP: 127.0.0.1") 31 | terminal.Println(fmt.Sprintf("Server Hostname: %s", os.Getenv("PROJECT_DOMAIN_1"))) 32 | terminal.Println("") 33 | terminal.Println("MySQL root username: root") 34 | terminal.Println(fmt.Sprintf("MySQL root password: %s", os.Getenv("MYSQL_ROOT_PASSWORD"))) 35 | terminal.Println("") 36 | terminal.Println(fmt.Sprintf("MySQL database name: %s", os.Getenv("MYSQL_DATABASE"))) 37 | terminal.Println(fmt.Sprintf("MySQL username: %s", os.Getenv("MYSQL_USER"))) 38 | terminal.Println(fmt.Sprintf("MySQL password: %s", os.Getenv("MYSQL_PASSWORD"))) 39 | terminal.Println("") 40 | terminal.Println("To login now, follow this link:") 41 | terminal.Println("") 42 | terminal.Println(fmt.Sprintf("Project URL: http://%s", os.Getenv("PROJECT_DOMAIN_1"))) 43 | terminal.Println(fmt.Sprintf("phpMyAdmin: http://%s:%s", os.Getenv("PROJECT_DOMAIN_1"), os.Getenv("PORT_PMA"))) 44 | terminal.Println(fmt.Sprintf("MailHog: http://%s:%s", os.Getenv("PROJECT_DOMAIN_1"), os.Getenv("PORT_MAILHOG_HTTP"))) 45 | terminal.Println("") 46 | } 47 | -------------------------------------------------------------------------------- /docker/php.yml: -------------------------------------------------------------------------------- 1 | 2 | php: 3 | build: 4 | context: config/php 5 | args: 6 | USER_ID: ${USER_ID} 7 | GROUP_ID: ${GROUP_ID} 8 | PHP_VERSION: ${PHP_VERSION} 9 | DEFAULT_TIMEZONE: ${DEFAULT_TIMEZONE} 10 | PHP_MEMORY_LIMIT: ${PHP_MEMORY_LIMIT} 11 | PHP_UPLOAD_MAX_FILESIZE: ${PHP_UPLOAD_MAX_FILESIZE} 12 | PHP_MAX_EXECUTION_TIME: ${PHP_MAX_EXECUTION_TIME} 13 | NODE_JS_VERSION: ${NODE_JS_VERSION} 14 | XDEBUG_CLIENT_PORT: ${XDEBUG_CLIENT_PORT} 15 | XDEBUG_START_WITH_REQUEST: ${XDEBUG_START_WITH_REQUEST} 16 | XDEBUG_REMOTE_HOST: ${XDEBUG_REMOTE_HOST} 17 | XDEBUG_REMOTE_CONNECT_BACK: ${XDEBUG_REMOTE_CONNECT_BACK} 18 | XDEBUG_FILE_LINK_FORMAT: ${XDEBUG_FILE_LINK_FORMAT} 19 | XDEBUG_IDE_KEY: ${XDEBUG_IDE_KEY} 20 | ports: 21 | - ${PORT_PHP}:9000 22 | - 8888:8888 23 | volumes: 24 | - ${PROJECT_PATH}:/var/www/project:cached 25 | - ${SF_COMMUNITY_PATH}:/var/www/symfony:cached 26 | - ./.composer/cache:/var/www/.composer/cache:cached 27 | - ${SSH_KEY_PATH}/id_rsa:/var/www/.ssh/id_rsa 28 | - ${SSH_KEY_PATH}/id_rsa.pub:/var/www/.ssh/id_rsa.pub 29 | - ${SSH_KEY_PATH}/known_hosts:/var/www/.ssh/known_hosts 30 | - ${USER_CONFIG_PATH}/.bash_history:/var/www/.bash_history 31 | - ${USER_CONFIG_PATH}/.bashrc:/var/www/.bashrc 32 | - ${USER_CONFIG_PATH}/.gitconfig:/var/www/.gitconfig 33 | - ${USER_CONFIG_PATH}/.gitignore:/var/www/.gitignore 34 | - ${USER_CONFIG_PATH}/bash_completion/console:/etc/bash_completion.d/console 35 | - ./config/php/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro 36 | - ./config/php/php-fpm.d/zz-docker.conf:/usr/local/etc/php-fpm.d/zz-docker.conf:ro 37 | - ./config/supervisor/conf.d/messenger-worker.conf:/etc/supervisor/conf.d/messenger-worker.conf 38 | - ./scripts/check_php_extensions.sh:/var/www/scripts/check_php_extensions.sh 39 | #php_depends_on 40 | -------------------------------------------------------------------------------- /.github/workflows/releaser.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | permissions: 8 | contents: write 9 | 10 | jobs: 11 | releaser: 12 | name: Release 13 | runs-on: ubuntu-latest 14 | steps: 15 | - 16 | name: Checkout 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | - 21 | name: Set up Go 22 | uses: actions/setup-go@v5 23 | with: 24 | go-version-file: 'go.mod' 25 | - name: Set AUTOUPDATE_CHANNEL on tags 26 | run: echo "AUTOUPDATE_CHANNEL=stable" >> $GITHUB_ENV 27 | if: startsWith(github.ref, 'refs/tags/v') 28 | - 29 | name: Prepare 30 | run: go generate ./ 31 | - 32 | name: Check Git status 33 | id: git 34 | run: | 35 | RESULT=$(git status --untracked-files=no --porcelain) 36 | echo "gitstatus=$RESULT" >> $GITHUB_OUTPUT 37 | - 38 | name: Check if go prepare updated generated Go code 39 | if: steps.git.outputs.gitstatus != '' 40 | run: | 41 | echo '"go generate" changed some Go generated code, run "go generate ./" locally and make a Pull Request with the changes' 42 | git diff 43 | exit 1 44 | - 45 | name: Test 46 | run: go test -v ./... 47 | - 48 | name: Validate build 49 | run: go run . 50 | - 51 | name: Run GoReleaser for snapshot 52 | uses: goreleaser/goreleaser-action@v6 53 | # only for PRs and push on branches 54 | if: ${{ !startsWith(github.ref, 'refs/tags/v') }} 55 | with: 56 | version: latest 57 | args: release --clean --snapshot --skip=publish,sign 58 | - 59 | name: Run GoReleaser 60 | uses: goreleaser/goreleaser-action@v6 61 | # only for tags 62 | if: startsWith(github.ref, 'refs/tags/v') 63 | with: 64 | version: latest 65 | args: release --clean 66 | 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GH_PAT }} 69 | - 70 | name: Archive binaries 71 | uses: actions/upload-artifact@v4 72 | with: 73 | retention-days: 5 74 | path: dist -------------------------------------------------------------------------------- /commands/root.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "docker-symfony/util" 5 | "fmt" 6 | "github.com/symfony-cli/console" 7 | "github.com/symfony-cli/terminal" 8 | "os" 9 | ) 10 | 11 | func CommonCommands() []*console.Command { 12 | d4dCommands := []*console.Command{ 13 | startCmd, 14 | passwordShowCmd, 15 | selfUpdateCmd, 16 | } 17 | 18 | return d4dCommands 19 | } 20 | 21 | func InitAppFunc(c *console.Context) error { 22 | 23 | return nil 24 | } 25 | 26 | // WelcomeAction displays a message when no command 27 | func WelcomeAction(c *console.Context) error { 28 | util.LoadEnvFile(envFile) 29 | 30 | terminal.Println("") 31 | console.ShowVersion(c) 32 | terminal.Println(c.App.Usage) 33 | terminal.Println("") 34 | terminal.Println("The following information has been set:") 35 | terminal.Println("") 36 | terminal.Println("Server IP: 127.0.0.1") 37 | terminal.Println(fmt.Sprintf("Server Hostname: %s", os.Getenv("PROJECT_DOMAIN_1"))) 38 | terminal.Println("") 39 | terminal.Println("To login now, follow this link:") 40 | terminal.Println("") 41 | terminal.Println(fmt.Sprintf("Project URL: http://%s", os.Getenv("PROJECT_DOMAIN_1"))) 42 | terminal.Println(fmt.Sprintf("phpMyAdmin: http://%s:%s", os.Getenv("PROJECT_DOMAIN_1"), os.Getenv("PORT_PMA"))) 43 | terminal.Println("") 44 | terminal.Println("Extra features:") 45 | terminal.Println(fmt.Sprintf("MailHog: http://%s:%s", os.Getenv("PROJECT_DOMAIN_1"), os.Getenv("PORT_MAILHOG_HTTP"))) 46 | terminal.Println(fmt.Sprintf("RabbitMQ: http://%s:%s", os.Getenv("PROJECT_DOMAIN_1"), os.Getenv("PORT_RABBITMQ_MANAGEMENT"))) 47 | terminal.Println(fmt.Sprintf("Elasticsearch: http://%s:%s", os.Getenv("PROJECT_DOMAIN_1"), os.Getenv("PORT_ELASTICSEARCH_HEAD"))) 48 | terminal.Println("") 49 | terminal.Println("Thank you for using Docker for Symfony. Should you have any questions, don't hesitate to contact us at support@d4d.lt") 50 | displayCommandsHelp(c, []*console.Command{}) 51 | terminal.Println("") 52 | terminal.Printf("Show all commands with %s help,\n", c.App.HelpName) 53 | terminal.Printf("Get help for a specific command with %s help COMMAND.\n", c.App.HelpName) 54 | 55 | return nil 56 | } 57 | 58 | func displayCommandsHelp(c *console.Context, cmds []*console.Command) { 59 | console.HelpPrinter(c.App.Writer, `{{range .}} {{.PreferredName}}{{"\t"}}{{.Usage}}{{"\n"}}{{end}}`, cmds) 60 | } 61 | -------------------------------------------------------------------------------- /config/nginx/project-ssl.conf.default: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | 4 | server_name 5 | __PROJECT_DOMAIN_1__ 6 | __PROJECT_DOMAIN_2__ 7 | __PROJECT_DOMAIN_3__ 8 | __PROJECT_DOMAIN_4__ 9 | ; 10 | root /var/www/project/__DOCUMENT_ROOT__; 11 | 12 | location / { 13 | return 301 https://$host$request_uri; 14 | } 15 | } 16 | 17 | server { 18 | server_name .ngrok.io; 19 | root /var/www/project/__DOCUMENT_ROOT__; 20 | 21 | include /etc/nginx/rewrite/project.conf; 22 | 23 | access_log /var/log/nginx/project_access.log; 24 | error_log /var/log/nginx/project_error.log; 25 | 26 | # strip app.php/ prefix if it is present 27 | rewrite ^/app\.php/?(.*)$ /$1 permanent; 28 | 29 | include __INCLUDE__; 30 | 31 | __INCLUDE_CACHE__ 32 | 33 | # pass the PHP script to FastCGI server from upstream phpfcgi 34 | location ~ ^/(app|app_dev|index|config|_intellij_phpdebug_validator)\.php(/|$) { 35 | fastcgi_pass php-upstream; 36 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 37 | include fastcgi_params; 38 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 39 | fastcgi_param SYMFONY_ENV dev; 40 | fastcgi_param HTTPS on; 41 | fastcgi_read_timeout __PHP_MAX_EXECUTION_TIME__; 42 | 43 | fastcgi_buffers __NGINX_FASTCGI_BUFFERS__; 44 | fastcgi_buffer_size __NGINX_FASTCGI_BUFFER_SIZE__; 45 | } 46 | 47 | client_max_body_size __PHP_UPLOAD_MAX_FILESIZE__; 48 | } 49 | 50 | server { 51 | listen 443 ssl http2 default_server; 52 | 53 | ssl_certificate /etc/nginx/ssl/d4d.pem; 54 | ssl_certificate_key /etc/nginx/ssl/d4d-key.pem; 55 | 56 | server_name 57 | __PROJECT_DOMAIN_1__ 58 | __PROJECT_DOMAIN_2__ 59 | __PROJECT_DOMAIN_3__ 60 | __PROJECT_DOMAIN_4__ 61 | ; 62 | root /var/www/project/__DOCUMENT_ROOT__; 63 | 64 | include /etc/nginx/rewrite/project.conf; 65 | 66 | access_log /var/log/nginx/project_access.log; 67 | error_log /var/log/nginx/project_error.log; 68 | 69 | # strip app.php/ prefix if it is present 70 | rewrite ^/app\.php/?(.*)$ /$1 permanent; 71 | 72 | include __INCLUDE__; 73 | 74 | __INCLUDE_CACHE__ 75 | 76 | # pass the PHP script to FastCGI server from upstream phpfcgi 77 | location ~ ^/(app|app_dev|index|config|_intellij_phpdebug_validator)\.php(/|$) { 78 | fastcgi_pass php-upstream; 79 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 80 | include fastcgi_params; 81 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 82 | fastcgi_param SYMFONY_ENV dev; 83 | fastcgi_param HTTPS on; 84 | fastcgi_read_timeout __PHP_MAX_EXECUTION_TIME__; 85 | 86 | fastcgi_buffers __NGINX_FASTCGI_BUFFERS__; 87 | fastcgi_buffer_size __NGINX_FASTCGI_BUFFER_SIZE__; 88 | } 89 | 90 | client_max_body_size __PHP_UPLOAD_MAX_FILESIZE__; 91 | } -------------------------------------------------------------------------------- /user/bash_completion/console: -------------------------------------------------------------------------------- 1 | # This file is part of the Symfony package. 2 | # 3 | # (c) Fabien Potencier 4 | # 5 | # For the full copyright and license information, please view 6 | # https://symfony.com/doc/current/contributing/code/license.html 7 | 8 | _sf_console() { 9 | # Use newline as only separator to allow space in completion values 10 | IFS=$'\n' 11 | local sf_cmd="${COMP_WORDS[0]}" 12 | 13 | # for an alias, get the real script behind it 14 | if [[ $(type -t $sf_cmd) == "alias" ]]; then 15 | sf_cmd=$(alias $sf_cmd | sed -E "s/alias $sf_cmd='(.*)'/\1/") 16 | else 17 | sf_cmd=$(type -p $sf_cmd) 18 | fi 19 | 20 | if [ ! -x "$sf_cmd" ]; then 21 | return 1 22 | fi 23 | 24 | local cur prev words cword 25 | _get_comp_words_by_ref -n := cur prev words cword 26 | 27 | local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-S6.1.7") 28 | for w in ${words[@]}; do 29 | w=$(printf -- '%b' "$w") 30 | # remove quotes from typed values 31 | quote="${w:0:1}" 32 | if [ "$quote" == \' ]; then 33 | w="${w%\'}" 34 | w="${w#\'}" 35 | elif [ "$quote" == \" ]; then 36 | w="${w%\"}" 37 | w="${w#\"}" 38 | fi 39 | # empty values are ignored 40 | if [ ! -z "$w" ]; then 41 | completecmd+=("-i$w") 42 | fi 43 | done 44 | 45 | local sfcomplete 46 | if sfcomplete=$(${completecmd[@]} 2>&1); then 47 | local quote suggestions 48 | quote=${cur:0:1} 49 | 50 | # Use single quotes by default if suggestions contains backslash (FQCN) 51 | if [ "$quote" == '' ] && [[ "$sfcomplete" =~ \\ ]]; then 52 | quote=\' 53 | fi 54 | 55 | if [ "$quote" == \' ]; then 56 | # single quotes: no additional escaping (does not accept ' in values) 57 | suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\n' "$quote" "$s" "$quote"; done) 58 | elif [ "$quote" == \" ]; then 59 | # double quotes: double escaping for \ $ ` " 60 | suggestions=$(for s in $sfcomplete; do 61 | s=${s//\\/\\\\} 62 | s=${s//\$/\\\$} 63 | s=${s//\`/\\\`} 64 | s=${s//\"/\\\"} 65 | printf $'%q%q%q\n' "$quote" "$s" "$quote"; 66 | done) 67 | else 68 | # no quotes: double escaping 69 | suggestions=$(for s in $sfcomplete; do printf $'%q\n' $(printf '%q' "$s"); done) 70 | fi 71 | COMPREPLY=($(IFS=$'\n' compgen -W "$suggestions" -- $(printf -- "%q" "$cur"))) 72 | __ltrim_colon_completions "$cur" 73 | else 74 | if [[ "$sfcomplete" != *"Command \"_complete\" is not defined."* ]]; then 75 | >&2 echo 76 | >&2 echo $sfcomplete 77 | fi 78 | 79 | return 1 80 | fi 81 | } 82 | 83 | complete -F _sf_console console -------------------------------------------------------------------------------- /config/nginx/Dockerfile.build: -------------------------------------------------------------------------------- 1 | ARG DEBIAN_VERSION 2 | 3 | FROM debian:${DEBIAN_VERSION} 4 | 5 | ARG PROJECT_DOMAIN_1 6 | ARG PROJECT_DOMAIN_2 7 | ARG PROJECT_DOMAIN_3 8 | ARG PROJECT_DOMAIN_4 9 | ARG DOCUMENT_ROOT 10 | ARG SYMFONY_FRONT_CONTROLLER 11 | ARG PHP_MAX_EXECUTION_TIME 12 | ARG PHP_UPLOAD_MAX_FILESIZE 13 | 14 | ARG PORT_PHP 15 | 16 | LABEL maintainer="Vasilij Dusko " 17 | 18 | RUN apt-get update \ 19 | && apt-get install --no-install-recommends --no-install-suggests -y \ 20 | curl gnupg2 ca-certificates lsb-release debian-archive-keyring \ 21 | && curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ 22 | | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \ 23 | && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg \ 24 | && echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ 25 | http://nginx.org/packages/debian `lsb_release -cs` nginx" \ 26 | | tee /etc/apt/sources.list.d/nginx.list \ 27 | && printf 'Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n' > /etc/apt/preferences.d/99nginx \ 28 | && apt-get update \ 29 | && apt-get install --no-install-recommends --no-install-suggests -y \ 30 | nginx \ 31 | gettext-base \ 32 | nano \ 33 | && apt-get remove --purge -y gnupg2 \ 34 | && apt-get -y --purge autoremove \ 35 | && apt-get clean && rm -rf /var/lib/apt/lists/* 36 | 37 | COPY project.conf /etc/nginx/sites-available/ 38 | COPY rewrite/project.conf /etc/nginx/rewrite/ 39 | 40 | COPY ["d4d/cache.conf", "d4d/sf.conf", "/etc/nginx/d4d/"] 41 | __D4D_SSL__ 42 | 43 | # optional commands to run at shell inside container at build time 44 | # this one adds package repo for nginx from nginx.org and installs it 45 | # forward request and error logs to docker log collector 46 | 47 | RUN ln -sf /dev/stdout /var/log/nginx/access.log \ 48 | && ln -sf /dev/stderr /var/log/nginx/error.log \ 49 | && mkdir -p /etc/nginx/sites-available \ 50 | && mkdir -p /etc/nginx/sites-enabled \ 51 | && mkdir -p /etc/nginx/d4d \ 52 | && mkdir -p /etc/nginx/rewrite \ 53 | && sed -i 's#__PROJECT_DOMAIN_1__#'"${PROJECT_DOMAIN_1}"'#g' /etc/nginx/sites-available/project.conf \ 54 | && sed -i 's#__PROJECT_DOMAIN_2__#'"${PROJECT_DOMAIN_2}"'#g' /etc/nginx/sites-available/project.conf \ 55 | && sed -i 's#__PROJECT_DOMAIN_3__#'"${PROJECT_DOMAIN_3}"'#g' /etc/nginx/sites-available/project.conf \ 56 | && sed -i 's#__PROJECT_DOMAIN_4__#'"${PROJECT_DOMAIN_4}"'#g' /etc/nginx/sites-available/project.conf \ 57 | && sed -i 's#__DOCUMENT_ROOT__#'"${DOCUMENT_ROOT}"'#g' /etc/nginx/sites-available/project.conf \ 58 | && sed -i 's#__SYMFONY_FRONT_CONTROLLER__#'"${SYMFONY_FRONT_CONTROLLER}"'#g' /etc/nginx/sites-available/project.conf \ 59 | && sed -i 's#__PHP_MAX_EXECUTION_TIME__#'"${PHP_MAX_EXECUTION_TIME}"'#g' /etc/nginx/sites-available/project.conf \ 60 | && sed -i 's#__PHP_UPLOAD_MAX_FILESIZE__#'"${PHP_UPLOAD_MAX_FILESIZE}"'#g' /etc/nginx/sites-available/project.conf \ 61 | && ln -s /etc/nginx/sites-available/project.conf /etc/nginx/sites-enabled/project.conf \ 62 | && rm -rf /etc/nginx/sites-enabled/default \ 63 | && echo "upstream php-upstream { server php:${PORT_PHP}; }" > /etc/nginx/conf.d/upstream.conf 64 | 65 | CMD ["nginx", "-g", "daemon off;"] 66 | # required: run this command when container is launched 67 | # only one CMD allowed, so if there are multiple, last one wins -------------------------------------------------------------------------------- /config/php/Dockerfile.build: -------------------------------------------------------------------------------- 1 | ARG PHP_VERSION 2 | 3 | FROM php:${PHP_VERSION}-fpm 4 | 5 | ARG DEFAULT_TIMEZONE 6 | ARG PHP_MEMORY_LIMIT 7 | ARG PHP_MAX_EXECUTION_TIME 8 | ARG PHP_UPLOAD_MAX_FILESIZE 9 | 10 | ARG NODE_JS_VERSION 11 | 12 | ARG USER_ID 13 | ARG GROUP_ID 14 | 15 | ARG XDEBUG_CLIENT_PORT 16 | ARG XDEBUG_START_WITH_REQUEST 17 | ARG XDEBUG_REMOTE_HOST 18 | ARG XDEBUG_REMOTE_CONNECT_BACK 19 | ARG XDEBUG_FILE_LINK_FORMAT 20 | ARG XDEBUG_IDE_KEY 21 | 22 | ARG WKHTMLTOPDF_VERSION 23 | 24 | LABEL maintainer="Vasilij Dusko " 25 | 26 | RUN __SYMFONY_CLI__ 27 | apt-get update && \ 28 | apt-get install --no-install-recommends --no-install-suggests -y \ 29 | __PACKAGE_LIST__ \ 30 | __CLEANUP__ 31 | 32 | # Install PHP extensions. Type docker-php-ext-install to see available extensions 33 | RUN __PHP_EXT_CONFIGURE__ 34 | __PHP_EXT_INSTALL__ 35 | __PECL_INSTALL__ 36 | __PHP_EXT_ENABLE__ 37 | && ln -snf /usr/share/zoneinfo/${DEFAULT_TIMEZONE} /etc/localtime && echo ${DEFAULT_TIMEZONE} > /etc/timezone \ 38 | && printf '[PHP]\ndate.timezone = "%s"\n' ${DEFAULT_TIMEZONE} > $PHP_INI_DIR/conf.d/tzone.ini \ 39 | && printf '[CUSTOM]\nmemory_limit = "%s"\n' ${PHP_MEMORY_LIMIT} >> $PHP_INI_DIR/conf.d/custom.ini \ 40 | && printf '\npost_max_size = %s\n' ${PHP_UPLOAD_MAX_FILESIZE} >> $PHP_INI_DIR/conf.d/custom.ini \ 41 | && printf '\nupload_max_filesize = %s\n' ${PHP_UPLOAD_MAX_FILESIZE} >> $PHP_INI_DIR/conf.d/custom.ini \ 42 | && printf '\nmax_execution_time = %s\n' ${PHP_MAX_EXECUTION_TIME} >> $PHP_INI_DIR/conf.d/custom.ini \ 43 | && printf '\nxdebug.file_link_format = "%s"\n' ${XDEBUG_FILE_LINK_FORMAT} >> $PHP_INI_DIR/conf.d/custom.ini \ 44 | && printf '\nxdebug.idekey = "%s"\n' ${XDEBUG_IDE_KEY} >> $PHP_INI_DIR/conf.d/custom.ini \ 45 | __RABBIT_MQ__ 46 | __MONGODB__ 47 | __XDEBUG__ 48 | # Install composer 49 | && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ 50 | && php composer-setup.php \ 51 | && php -r "unlink('composer-setup.php');" \ 52 | && mv composer.phar /usr/local/bin/composer \ 53 | && mkdir -p /var/www/.composer \ 54 | && printf '{\n "config": {\n "cache-dir": "/var/www/.composer/cache"\n }\n}' >> /var/www/.composer/config.json \ 55 | && chown -R ${USER_ID}:${GROUP_ID} /var/www/.composer \ 56 | && chown ${USER_ID}:${GROUP_ID} /var/www \ 57 | # npm & node 58 | __NODEJS__ \ 59 | # Yarn package manager 60 | # bugfix: remove cmdtest to install yarn correctly. 61 | __YARN__ \ 62 | # Install wkhtmltopdf 63 | __WKHTMLTOPDF__ \ 64 | __BLACKFIRE__ \ 65 | && curl -L __CURL_INSECURE__ https://cs.symfony.com/download/php-cs-fixer-v3.phar -o /usr/bin/php-cs-fixer && chmod a+x /usr/bin/php-cs-fixer \ 66 | && curl -L __CURL_INSECURE__ https://github.com/fabpot/local-php-security-checker/releases/download/v2.0.3/local-php-security-checker_2.0.3_linux_amd64 -o /usr/bin/local-php-security-checker && chmod a+x /usr/bin/local-php-security-checker \ 67 | && curl -L __CURL_INSECURE__ https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar -o /usr/local/bin/phpstan && chmod a+x /usr/local/bin/phpstan \ 68 | && curl -L __CURL_INSECURE__ https://github.com/deployphp/deployer/releases/latest/download/deployer.phar -o /usr/local/bin/dep && chmod a+x /usr/local/bin/dep \ 69 | 70 | && apt-get remove --purge -y gnupg2 \ 71 | && apt-get -y --purge autoremove \ 72 | __CLEANUP__ 73 | 74 | # Copy xdebug and php config. 75 | COPY conf.d/* /usr/local/etc/php/conf.d/ 76 | 77 | # Map user id from host user when it's provided 78 | RUN if [ ! -z ${USER_ID} ] && [ ${USER_ID} -ne 0 ]; then usermod -u ${USER_ID} www-data; fi \ 79 | && if [ ! -z ${GROUP_ID} ] && [ ${GROUP_ID} -ne 0 ]; then groupmod -g ${GROUP_ID} www-data; fi 80 | 81 | # set default user and working directory 82 | USER ${USER_ID} 83 | WORKDIR /var/www/project 84 | -------------------------------------------------------------------------------- /.env.dist: -------------------------------------------------------------------------------- 1 | # Project's path (absolute or relative) 2 | PROJECT_PATH=./project 3 | 4 | # Symfony Community path (absolute or relative) 5 | SF_COMMUNITY_PATH=./symfony 6 | 7 | # Project domains 8 | PROJECT_DOMAIN_1=symfony.local 9 | PROJECT_DOMAIN_2=symfony2.local 10 | PROJECT_DOMAIN_3=symfony3.local 11 | PROJECT_DOMAIN_4=symfony4.local 12 | 13 | # Nginx document_root 14 | DOCUMENT_ROOT=public 15 | 16 | # Symfony front controller 17 | SYMFONY_FRONT_CONTROLLER=index.php 18 | 19 | NGINX_SSL_PATH=./user/nginx/ssl/ 20 | NGINX_LOG_PATH=./var/log/nginx/ 21 | MONGODB_LOG_PATH=./var/log/mongodb/ 22 | MYSQL_DATA_PATH=./var/lib/mysql/ 23 | MONGODB_DATA_PATH=./var/lib/mongodb/ 24 | MYSQL_DUMP_PATH=./db 25 | 26 | # Linux users: Set this to user id from the host system to avoid permission problems. 27 | # Get the user id with: "id -u" 28 | USER_ID= 29 | GROUP_ID= 30 | 31 | # Security 32 | SSH_KEY_PATH=~/.ssh 33 | 34 | # User main directory where user configuration is stored like /root 35 | USER_CONFIG_PATH=./user 36 | 37 | # Debian OS available versions: jessie, stretch, buster, bullseye, bookworm 38 | DEBIAN_VERSION=bookworm 39 | 40 | # PHP available versions: 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, 8.4 41 | PHP_VERSION=8.4 42 | 43 | # Nginx settings 44 | NGINX_CACHE=yes 45 | NGINX_SSL=no 46 | # Nginx custom configuration 47 | NGINX_FASTCGI_BUFFERS="8 8k" 48 | NGINX_FASTCGI_BUFFER_SIZE=8k 49 | 50 | # MySQL available versions: 5.6, 5.7, 8.0, 8.1, 8.2, 8.3, 8.4 51 | MYSQL_VERSION=8.4 52 | # MariaDB available versions: 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 10.10, 10.11, 11.0, 11.1, 11.2, 11.3, 11.4 53 | MARIADB_VERSION=11.4 54 | # MySQL vs MariaDB. Possible values: mysql, mariadb 55 | MYSQL_INST=mariadb 56 | 57 | MYSQL_MAX_ALLOWED_PACKET=64M 58 | MYSQL_INNODB_LOG_FILE_SIZE=48M 59 | MYSQL_WAIT_TIMEOUT=28800 60 | 61 | # Default MySQL character set and collation 62 | MYSQL_CHARACTER_SET_SERVER=utf8mb4 63 | MYSQL_COLLATION_SERVER=utf8mb4_unicode_ci 64 | 65 | DEFAULT_TIMEZONE=Europe/Vilnius 66 | 67 | # PHP settings 68 | PHP_MEMORY_LIMIT=2048M 69 | PHP_MAX_EXECUTION_TIME=30 70 | # upload_max_filesize, post_max_size 71 | PHP_UPLOAD_MAX_FILESIZE=10240M 72 | 73 | # phpMyAdmin configuration 74 | PMA_AUTO_LOGIN=no 75 | PMA_AUTO_LOGIN_ROOT=no 76 | 77 | # Open ports 78 | PORT_MYSQL=3306 79 | PORT_NGINX=80 80 | PORT_NGINX_SSL=443 81 | PORT_PHP=9000 82 | PORT_MAIL_SMTP=1025 83 | PORT_MAIL_HTTP=8025 84 | PORT_PMA=8080 85 | PORT_RABBITMQ_TCP_LISTENER=5673 86 | PORT_RABBITMQ_MANAGEMENT=15672 87 | 88 | PORT_ELASTICSEARCH=9200 89 | PORT_ELASTICSEARCH_HEAD=9100 90 | PORT_ELASTICSEARCH_KIBANA=5601 91 | 92 | PORT_NGROK=4040 93 | 94 | # Xdebug 95 | XDEBUG=no 96 | XDEBUG_CONFIG=1 97 | XDEBUG_START_WITH_REQUEST=yes 98 | XDEBUG_CLIENT_PORT=9000 99 | XDEBUG_IDE_KEY=PHPSTORM 100 | XDEBUG_FILE_LINK_FORMAT="phpstorm://open?file=%f&line=%l" 101 | 102 | # Linux users, uncomment: 103 | # XDEBUG_REMOTE_CONNECT_BACK=1 104 | # If you want to XDEBUG from CLI, don't use XDEBUG_REMOTE_CONNECT_BACK: 105 | # Enter the IP adress of your Docker bridge, to get this address: 106 | # $ ip -f inet addr show docker0 | grep -Po 'inet \K[\d.]+' 107 | # XDEBUG_REMOTE_HOST= 108 | 109 | # macOS uncomment (Docker for Mac CE version >= 17.06.0): 110 | # XDEBUG_REMOTE_HOST=docker.for.mac.localhost 111 | # macOS uncomment (Docker for Mac CE version >= 17.12.0): 112 | # XDEBUG_REMOTE_HOST=docker.for.mac.host.internal 113 | 114 | # Windows uncomment (Docker for Windows CE >= 17.06.0): 115 | # XDEBUG_REMOTE_HOST=docker.for.win.localhost 116 | 117 | # If you're running an older version of Docker you can use this: 118 | # Support for this is deprecated! 119 | # For Docker for macOS or Windows, you need to provide your IP address. 120 | # For macOS, you can create an alias of your loopback (127.0.0.1) address 121 | # with the following command: 122 | # 123 | # sudo ifconfig lo0 alias 10.254.254.254 255.255.255.0 124 | # 125 | # If you are running Linux and sharing your .env with mixed-OS team members, 126 | # you can also create a URL alias using the following: 127 | # 128 | # sudo ip -4 addr add 10.254.254.254/32 dev lo 129 | # XDEBUG_REMOTE_HOST=10.254.254.254 130 | 131 | # Pipe XDebug logs to STDOUT? You only need to do this if Xdebug isn't working. 132 | # XDEBUG_CONFIG=remote_log=/dev/stdout 133 | 134 | # Xdebug IDE configuration. 135 | PHP_IDE_CONFIG=serverName=symfony-docker 136 | 137 | # Node JS available versions: 16, 18, 20, 20, 21, 22, 23 138 | NODE_JS_VERSION=23 139 | 140 | CLEAN_NGINX_LOGS=no 141 | CLEAN_SF_logs=no 142 | 143 | # compose.yaml configuration 144 | NODEJS=no 145 | YARN=no 146 | WKHTMLTOPDF=no 147 | MAILHOG=no 148 | MAILPIT=no 149 | PMA=no 150 | REDIS=no 151 | RABBITMQ=no 152 | SUPERVISOR=no 153 | ELASTICSEARCH=no 154 | NGROK=no 155 | MYSQL=yes 156 | MONGODB=no 157 | BLACKFIRE=no 158 | ELK=no 159 | SF_CLI=no 160 | DOCKER_ENV_PHP=no 161 | PHP_IMAGICK=no 162 | PHP_GD=no 163 | PHP_IMAP=no 164 | 165 | EXTERNAL_NETWORK=no 166 | 167 | RABBITMQ_VERSION=4.0.6 168 | ELASTICSEARCH_VERSION=6.8.23 169 | ELK_VERSION=7.16.0 170 | # MongoDB available versions: 4.2.24, 4.4.29, 5.0.30, 6.0.19 171 | MONGODB_VERSION=6.0.19 172 | # wkhtmltopdf available versions: 0.12.3, 0.12.4, 0.12.5, 0.12.6 173 | WKHTMLTOPDF_VERSION=0.12.3 174 | 175 | NGROK_AUTH= 176 | 177 | DEFAULT_CONTAINER=php 178 | 179 | -------------------------------------------------------------------------------- /util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bufio" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/x509" 8 | "encoding/pem" 9 | "fmt" 10 | "github.com/joho/godotenv" 11 | "github.com/sethvargo/go-password/password" 12 | "io" 13 | "log" 14 | "net/http" 15 | "os" 16 | "os/exec" 17 | "regexp" 18 | "strings" 19 | 20 | "golang.org/x/crypto/ssh" 21 | ) 22 | 23 | func IsCommandExist(cmd string) bool { 24 | _, err := exec.LookPath(cmd) 25 | 26 | return err == nil 27 | } 28 | 29 | func Sed(old, new, filePath string) error { 30 | fileData, err := os.ReadFile(filePath) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | m1 := regexp.MustCompile(old) 36 | 37 | fileString := string(fileData) 38 | fileString = m1.ReplaceAllString(string(fileData), new) 39 | fileData = []byte(fileString) 40 | 41 | err = os.WriteFile(filePath, fileData, 0644) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | return nil 47 | } 48 | 49 | func AppendFile(filePath string, data string) { 50 | f, err := os.OpenFile(filePath, 51 | os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 52 | if err != nil { 53 | log.Println(err) 54 | } 55 | defer f.Close() 56 | if _, err := f.WriteString(data); err != nil { 57 | log.Println(err) 58 | } 59 | } 60 | 61 | func FileGetContents(filename string) string { 62 | fileData, err := os.ReadFile(filename) 63 | if err != nil { 64 | os.Exit(1) 65 | } 66 | 67 | return string(fileData) 68 | } 69 | 70 | func GeneratePassword(length int) string { 71 | res, err := password.Generate(length, 10, 0, false, false) 72 | if err != nil { 73 | log.Fatal(err) 74 | } 75 | 76 | return res 77 | } 78 | 79 | func LoadEnvFile(filename string) { 80 | err := godotenv.Load(filename) 81 | if err != nil { 82 | log.Fatalf("Some error occured. Err: %s", err) 83 | } 84 | } 85 | 86 | func MakeSSHKeyPair() (string, string, error) { 87 | privateKey, err := rsa.GenerateKey(rand.Reader, 4096) 88 | if err != nil { 89 | return "", "", err 90 | } 91 | 92 | // generate and write private key as PEM 93 | var privKeyBuf strings.Builder 94 | 95 | privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)} 96 | if err := pem.Encode(&privKeyBuf, privateKeyPEM); err != nil { 97 | return "", "", err 98 | } 99 | 100 | // generate and write public key 101 | pub, err := ssh.NewPublicKey(&privateKey.PublicKey) 102 | if err != nil { 103 | return "", "", err 104 | } 105 | 106 | var pubKeyBuf strings.Builder 107 | pubKeyBuf.Write(ssh.MarshalAuthorizedKey(pub)) 108 | 109 | return pubKeyBuf.String(), privKeyBuf.String(), nil 110 | } 111 | 112 | func GetCurrentDir() string { 113 | if currentDir, err := os.Getwd(); err == nil { 114 | return currentDir 115 | } 116 | 117 | return "" 118 | } 119 | 120 | func FileExists(filename string) bool { 121 | info, err := os.Stat(filename) 122 | if os.IsNotExist(err) { 123 | return false 124 | } 125 | 126 | return !info.IsDir() 127 | } 128 | 129 | func Copy(src, dst string) (int64, error) { 130 | sourceFileStat, err := os.Stat(src) 131 | if err != nil { 132 | return 0, err 133 | } 134 | 135 | if !sourceFileStat.Mode().IsRegular() { 136 | return 0, fmt.Errorf("%s is not a regular file", src) 137 | } 138 | 139 | source, err := os.Open(src) 140 | if err != nil { 141 | return 0, err 142 | } 143 | defer source.Close() 144 | 145 | destination, err := os.Create(dst) 146 | if err != nil { 147 | return 0, err 148 | } 149 | defer destination.Close() 150 | nBytes, err := io.Copy(destination, source) 151 | return nBytes, err 152 | } 153 | 154 | func ExecCommand(cmdName string) { 155 | cmdArgs := strings.Fields(cmdName) 156 | 157 | cmd := exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...) 158 | stdout, _ := cmd.StdoutPipe() 159 | cmd.Start() 160 | 161 | scanner := bufio.NewScanner(stdout) 162 | scanner.Split(bufio.ScanLines) 163 | for scanner.Scan() { 164 | m := scanner.Text() 165 | fmt.Println(m) 166 | } 167 | cmd.Wait() 168 | } 169 | 170 | func CreateFileIfNotExists(filename string) { 171 | if !FileExists(filename) { 172 | os.Create(filename) 173 | } 174 | } 175 | 176 | func Mkdir(dirs []string, perm os.FileMode) { 177 | for i := 0; i < len(dirs); i++ { 178 | os.Mkdir(dirs[i], perm) 179 | } 180 | } 181 | 182 | func Chmod(name string, mode os.FileMode) { 183 | err := os.Chmod(name, mode) 184 | if err != nil { 185 | log.Fatal(err) 186 | } 187 | } 188 | 189 | func DownloadFile(filepath string, url string) (err error) { 190 | // Create the file 191 | out, err := os.Create(filepath) 192 | if err != nil { 193 | return err 194 | } 195 | defer out.Close() 196 | 197 | // Get the data 198 | resp, err := http.Get(url) 199 | if err != nil { 200 | return err 201 | } 202 | defer resp.Body.Close() 203 | 204 | // Check server response 205 | if resp.StatusCode != http.StatusOK { 206 | return fmt.Errorf("bad status: %s", resp.Status) 207 | } 208 | 209 | // Writer the body to file 210 | _, err = io.Copy(out, resp.Body) 211 | if err != nil { 212 | return err 213 | } 214 | 215 | return nil 216 | } 217 | 218 | func Contains(slice []string, target string) bool { 219 | for _, value := range slice { 220 | if value == target { 221 | return true 222 | } 223 | } 224 | return false 225 | } 226 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= 2 | github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 3 | github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 4 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 7 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 8 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= 9 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 10 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 11 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= 12 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 13 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 14 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 15 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 16 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 17 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 18 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 19 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 20 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 21 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 22 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 23 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 24 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 25 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 26 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 27 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 28 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 29 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 30 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 31 | github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= 32 | github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= 33 | github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= 34 | github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 35 | github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 36 | github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= 37 | github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= 38 | github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU= 39 | github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs= 40 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 41 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 42 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 43 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 44 | github.com/symfony-cli/console v1.1.5 h1:zN1n0cN5jTYx+wf+AxEtNprPGsoyYtgsQHia1tLFgME= 45 | github.com/symfony-cli/console v1.1.5/go.mod h1:AB4ZxA593cyS/1NhwnDEUChIPaGuddFqooipam1vyS8= 46 | github.com/symfony-cli/terminal v1.0.7 h1:57L9PUTE2cHfQtP8Ti8dyiiPEYlQ1NBIDpMJ3RPEGPc= 47 | github.com/symfony-cli/terminal v1.0.7/go.mod h1:Etv22IyeGiMoIQPPj51hX31j7xuYl1njyuAFkrvybqU= 48 | golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= 49 | golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 50 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 51 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 52 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 53 | golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= 54 | golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 55 | golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= 56 | golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= 57 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 58 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 59 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 60 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 61 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 62 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker for Symfony (PHP-FPM - NGINX - MySQL) 2 | 3 | Docker symfony gives you everything you need for developing Symfony application. This complete stack run with docker and docker-compose. 4 | 5 | # Installation 6 | 7 | ## Install the latest Docker CE version 8 | If you are running on Linux: 9 | ``` 10 | curl -fsSL https://get.docker.com -o get-docker.sh && 11 | sh get-docker.sh 12 | ``` 13 | 14 | If you would like to use Docker as a non-root user, you should now consider 15 | adding your user to the "docker" group with something like: 16 | 17 | ``` 18 | sudo usermod -aG docker ${USER} 19 | ``` 20 | 21 | ## Install the latest Docker Compose 22 | 23 | If you are running on Linux: 24 | ``` 25 | sudo curl -L "https://github.com/docker/compose/releases/download/v2.28.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose 26 | ``` 27 | 28 | # Configuration 29 | 1. Create a `.env` from the `.env.dist` file. Adapt it according to your symfony application 30 | 31 | ```bash 32 | cp .env.dist .env 33 | ``` 34 | 35 | 2. Build / run containers 36 | ``` 37 | ./d4d start 38 | ``` 39 | 40 | 3. Update your system host file (add symfony.local) 41 | ```bash 42 | # UNIX only: get containers IP address and update host (replace IP according to your configuration) 43 | $ sudo echo $(docker network inspect bridge | grep Gateway | grep -o -E '[0-9\.]+') "symfony.local" >> /etc/hosts 44 | ``` 45 | 46 | **Note:** For **OS X**, please take a look [here](https://docs.docker.com/docker-for-mac/networking/). 47 | 48 | 4. Prepare Symfony app 49 | 1. Get your logins to access MySQL server 50 | `./d4d passwd show` 51 | 52 | 2. Update 53 | 54 | a) SF2, SF3: app/config/parameters.yml 55 | 56 | ``` 57 | # ./project/app/config/parameters.yml 58 | parameters: 59 | database_host: mysql 60 | database_port: ~ 61 | database_name: db_name 62 | database_user: db_user 63 | database_password: db_password (random password) 64 | ``` 65 | 66 | b) SF4, SF5, SF6: .env 67 | ``` 68 | DATABASE_URL=mysql://db_user:db_password@mysql:3306/db_name 69 | MAILER_URL=smtp://mailhog:1025 70 | ``` 71 | 3. Composer install & create database 72 | ```bash 73 | $ docker-compose exec php bash 74 | $ composer create-project symfony/website-skeleton my-project 75 | 76 | # Symfony 2 77 | $ sf doctrine:database:create 78 | $ sf doctrine:schema:update --force 79 | # Only if you have `doctrine/doctrine-fixtures-bundle` installed 80 | $ sf doctrine:fixtures:load --no-interaction 81 | 82 | # Symfony 3 83 | $ sf3 doctrine:database:create 84 | $ sf3 doctrine:schema:update --force 85 | # Only if you have `doctrine/doctrine-fixtures-bundle` installed 86 | $ sf3 doctrine:fixtures:load --no-interaction 87 | 88 | # Symfony 4 89 | $ sf4 doctrine:database:create 90 | $ sf4 doctrine:schema:update --force 91 | # Only if you have `doctrine/doctrine-fixtures-bundle` installed 92 | $ sf4 doctrine:fixtures:load --no-interaction 93 | 94 | # Symfony 5 95 | $ sf5 doctrine:database:create 96 | $ sf5 doctrine:schema:update --force 97 | # Only if you have `doctrine/doctrine-fixtures-bundle` installed 98 | $ sf5 doctrine:fixtures:load --no-interaction 99 | 100 | # Symfony 6 101 | $ sf6 doctrine:database:create 102 | $ sf6 doctrine:schema:update --force 103 | # Only if you have `doctrine/doctrine-fixtures-bundle` installed 104 | $ sf6 doctrine:fixtures:load --no-interaction 105 | ``` 106 | 5. Enjoy :-) 107 | 108 | ## Usage 109 | 110 | Just run `./d4d start`, then: 111 | 112 | * Symfony app: visit [symfony.local](http://symfony.local) 113 | * Symfony dev mode: visit [symfony.local/app_dev.php](http://symfony.local/app_dev.php) 114 | * Logs (files location): logs/nginx and logs/symfony 115 | 116 | ## How it works? 117 | 118 | Have a look at the `compose.yaml` file, here are the `docker-compose` built images: 119 | 120 | * `nginx`: Nginx is one of the most popular web servers in the world and responsible for hosting some of the largest and highest-traffic sites on the internet. It is more resource-friendly than Apache in most cases and can be used as a web server or reverse proxy. 121 | * `php`: PHP is a popular general-purpose scripting language that is especially suited to web development. 122 | * `mysql:` MySQL is the most popular relational database management system. 123 | * `phpmyadmin`: phpMyAdmin was created so that users can interact with MySQL / MariaDB through a web interface. 124 | * `mailhog`: MailHog is an email testing tool for developers. 125 | * `redis`: Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster. 126 | 127 | This results in the following running containers: 128 | 129 | ```bash 130 | $ docker-compose ps 131 | Name Command State Ports 132 | --------------------------------------------------------------------------------------------------------------------- 133 | docker-symfony_mailhog_1 MailHog Up 0.0.0.0:1025->1025/tcp, 0.0.0.0:8025->8025/tcp 134 | docker-symfony_mysql_1 docker-entrypoint.sh --cha ... Up 0.0.0.0:3306->3306/tcp 135 | docker-symfony_nginx_1 nginx -g daemon off; Up 0.0.0.0:80->80/tcp 136 | docker-symfony_php_1 docker-php-entrypoint php-fpm Up 9000/tcp 137 | docker-symfony_phpmyadmin_1 /docker-entrypoint.sh apac ... Up 0.0.0.0:8080->80/tcp 138 | docker-symfony_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp 139 | ``` 140 | 141 | # PHP extensions 142 | | Extension | PHP 7.1 | PHP 7.2 | PHP 7.3 | PHP 7.4 | PHP 8.0 | PHP 8.1 | PHP 8.2 | PHP 8.3 | PHP 8.4 | 143 | |-----------|---------|---------|---------|---------|---------|---------|---------|---------|---------| 144 | | amqp | 1.11.0 | 1.11.0 | 1.11.0 | 2.1.2 | 2.1.2 | 2.1.2 | 2.1.2 | 2.1.2 | 2.1.2 | 145 | | mongodb | 1.11.1 | 1.16.2 | 1.16.2 | 1.20.1 | 1.20.1 | 1.20.1 | 1.20.1 | 1.20.1 | 1.20.1 | 146 | | redis | 5.3.7 | 5.3.7 | 5.3.7 | 6.1.0 | 6.1.0 | 6.1.0 | 6.1.0 | 6.1.0 | 6.1.0 | 147 | | xdebug | 2.9.8 | 3.1.6 | 3.1.6 | 3.1.6 | 3.4.0 | 3.4.0 | 3.4.0 | 3.4.0 | 3.4.0 | 148 | 149 | # DirectAdmin support us! 150 | 151 |

152 | 153 | 154 | 155 |

156 | 157 | # JetBrains support us! 158 | 159 |

160 | 161 | 162 | 163 |

164 | 165 | # Blackfire.io support us! 166 |

167 | 168 | 169 | 170 |

171 | 172 | ## Get $200 to try DigitalOcean! 173 |

174 | DigitalOcean Referral Badge 175 |

-------------------------------------------------------------------------------- /config/php/php-fpm.d/www.conf: -------------------------------------------------------------------------------- 1 | ; Start a new pool named 'www'. 2 | ; the variable $pool can be used in any directive and will be replaced by the 3 | ; pool name ('www' here) 4 | [www] 5 | 6 | ; Per pool prefix 7 | ; It only applies on the following directives: 8 | ; - 'access.log' 9 | ; - 'slowlog' 10 | ; - 'listen' (unixsocket) 11 | ; - 'chroot' 12 | ; - 'chdir' 13 | ; - 'php_values' 14 | ; - 'php_admin_values' 15 | ; When not set, the global prefix (or NONE) applies instead. 16 | ; Note: This directive can also be relative to the global prefix. 17 | ; Default Value: none 18 | ;prefix = /path/to/pools/$pool 19 | 20 | ; Unix user/group of processes 21 | ; Note: The user is mandatory. If the group is not set, the default user's group 22 | ; will be used. 23 | user = www-data 24 | group = www-data 25 | 26 | ; The address on which to accept FastCGI requests. 27 | ; Valid syntaxes are: 28 | ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on 29 | ; a specific port; 30 | ; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on 31 | ; a specific port; 32 | ; 'port' - to listen on a TCP socket to all addresses 33 | ; (IPv6 and IPv4-mapped) on a specific port; 34 | ; '/path/to/unix/socket' - to listen on a unix socket. 35 | ; Note: This value is mandatory. 36 | listen = 127.0.0.1:9000 37 | 38 | ; Set listen(2) backlog. 39 | ; Default Value: 511 (-1 on FreeBSD and OpenBSD) 40 | ;listen.backlog = 511 41 | 42 | ; Set permissions for unix socket, if one is used. In Linux, read/write 43 | ; permissions must be set in order to allow connections from a web server. Many 44 | ; BSD-derived systems allow connections regardless of permissions. 45 | ; Default Values: user and group are set as the running user 46 | ; mode is set to 0660 47 | ;listen.owner = www-data 48 | ;listen.group = www-data 49 | ;listen.mode = 0660 50 | ; When POSIX Access Control Lists are supported you can set them using 51 | ; these options, value is a comma separated list of user/group names. 52 | ; When set, listen.owner and listen.group are ignored 53 | ;listen.acl_users = 54 | ;listen.acl_groups = 55 | 56 | ; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. 57 | ; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original 58 | ; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address 59 | ; must be separated by a comma. If this value is left blank, connections will be 60 | ; accepted from any ip address. 61 | ; Default Value: any 62 | ;listen.allowed_clients = 127.0.0.1 63 | 64 | ; Specify the nice(2) priority to apply to the pool processes (only if set) 65 | ; The value can vary from -19 (highest priority) to 20 (lower priority) 66 | ; Note: - It will only work if the FPM master process is launched as root 67 | ; - The pool processes will inherit the master process priority 68 | ; unless it specified otherwise 69 | ; Default Value: no set 70 | ; process.priority = -19 71 | 72 | ; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user 73 | ; or group is differrent than the master process user. It allows to create process 74 | ; core dump and ptrace the process for the pool user. 75 | ; Default Value: no 76 | ; process.dumpable = yes 77 | 78 | ; Choose how the process manager will control the number of child processes. 79 | ; Possible Values: 80 | ; static - a fixed number (pm.max_children) of child processes; 81 | ; dynamic - the number of child processes are set dynamically based on the 82 | ; following directives. With this process management, there will be 83 | ; always at least 1 children. 84 | ; pm.max_children - the maximum number of children that can 85 | ; be alive at the same time. 86 | ; pm.start_servers - the number of children created on startup. 87 | ; pm.min_spare_servers - the minimum number of children in 'idle' 88 | ; state (waiting to process). If the number 89 | ; of 'idle' processes is less than this 90 | ; number then some children will be created. 91 | ; pm.max_spare_servers - the maximum number of children in 'idle' 92 | ; state (waiting to process). If the number 93 | ; of 'idle' processes is greater than this 94 | ; number then some children will be killed. 95 | ; ondemand - no children are created at startup. Children will be forked when 96 | ; new requests will connect. The following parameter are used: 97 | ; pm.max_children - the maximum number of children that 98 | ; can be alive at the same time. 99 | ; pm.process_idle_timeout - The number of seconds after which 100 | ; an idle process will be killed. 101 | ; Note: This value is mandatory. 102 | pm = dynamic 103 | 104 | ; The number of child processes to be created when pm is set to 'static' and the 105 | ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. 106 | ; This value sets the limit on the number of simultaneous requests that will be 107 | ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. 108 | ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP 109 | ; CGI. The below defaults are based on a server without much resources. Don't 110 | ; forget to tweak pm.* to fit your needs. 111 | ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' 112 | ; Note: This value is mandatory. 113 | pm.max_children = 5 114 | 115 | ; The number of child processes created on startup. 116 | ; Note: Used only when pm is set to 'dynamic' 117 | ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 118 | pm.start_servers = 2 119 | 120 | ; The desired minimum number of idle server processes. 121 | ; Note: Used only when pm is set to 'dynamic' 122 | ; Note: Mandatory when pm is set to 'dynamic' 123 | pm.min_spare_servers = 1 124 | 125 | ; The desired maximum number of idle server processes. 126 | ; Note: Used only when pm is set to 'dynamic' 127 | ; Note: Mandatory when pm is set to 'dynamic' 128 | pm.max_spare_servers = 3 129 | 130 | ; The number of seconds after which an idle process will be killed. 131 | ; Note: Used only when pm is set to 'ondemand' 132 | ; Default Value: 10s 133 | ;pm.process_idle_timeout = 10s; 134 | 135 | ; The number of requests each child process should execute before respawning. 136 | ; This can be useful to work around memory leaks in 3rd party libraries. For 137 | ; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. 138 | ; Default Value: 0 139 | ;pm.max_requests = 500 140 | 141 | ; The URI to view the FPM status page. If this value is not set, no URI will be 142 | ; recognized as a status page. It shows the following informations: 143 | ; pool - the name of the pool; 144 | ; process manager - static, dynamic or ondemand; 145 | ; start time - the date and time FPM has started; 146 | ; start since - number of seconds since FPM has started; 147 | ; accepted conn - the number of request accepted by the pool; 148 | ; listen queue - the number of request in the queue of pending 149 | ; connections (see backlog in listen(2)); 150 | ; max listen queue - the maximum number of requests in the queue 151 | ; of pending connections since FPM has started; 152 | ; listen queue len - the size of the socket queue of pending connections; 153 | ; idle processes - the number of idle processes; 154 | ; active processes - the number of active processes; 155 | ; total processes - the number of idle + active processes; 156 | ; max active processes - the maximum number of active processes since FPM 157 | ; has started; 158 | ; max children reached - number of times, the process limit has been reached, 159 | ; when pm tries to start more children (works only for 160 | ; pm 'dynamic' and 'ondemand'); 161 | ; Value are updated in real time. 162 | ; Example output: 163 | ; pool: www 164 | ; process manager: static 165 | ; start time: 01/Jul/2011:17:53:49 +0200 166 | ; start since: 62636 167 | ; accepted conn: 190460 168 | ; listen queue: 0 169 | ; max listen queue: 1 170 | ; listen queue len: 42 171 | ; idle processes: 4 172 | ; active processes: 11 173 | ; total processes: 15 174 | ; max active processes: 12 175 | ; max children reached: 0 176 | ; 177 | ; By default the status page output is formatted as text/plain. Passing either 178 | ; 'html', 'xml' or 'json' in the query string will return the corresponding 179 | ; output syntax. Example: 180 | ; http://www.foo.bar/status 181 | ; http://www.foo.bar/status?json 182 | ; http://www.foo.bar/status?html 183 | ; http://www.foo.bar/status?xml 184 | ; 185 | ; By default the status page only outputs short status. Passing 'full' in the 186 | ; query string will also return status for each pool process. 187 | ; Example: 188 | ; http://www.foo.bar/status?full 189 | ; http://www.foo.bar/status?json&full 190 | ; http://www.foo.bar/status?html&full 191 | ; http://www.foo.bar/status?xml&full 192 | ; The Full status returns for each process: 193 | ; pid - the PID of the process; 194 | ; state - the state of the process (Idle, Running, ...); 195 | ; start time - the date and time the process has started; 196 | ; start since - the number of seconds since the process has started; 197 | ; requests - the number of requests the process has served; 198 | ; request duration - the duration in µs of the requests; 199 | ; request method - the request method (GET, POST, ...); 200 | ; request URI - the request URI with the query string; 201 | ; content length - the content length of the request (only with POST); 202 | ; user - the user (PHP_AUTH_USER) (or '-' if not set); 203 | ; script - the main script called (or '-' if not set); 204 | ; last request cpu - the %cpu the last request consumed 205 | ; it's always 0 if the process is not in Idle state 206 | ; because CPU calculation is done when the request 207 | ; processing has terminated; 208 | ; last request memory - the max amount of memory the last request consumed 209 | ; it's always 0 if the process is not in Idle state 210 | ; because memory calculation is done when the request 211 | ; processing has terminated; 212 | ; If the process is in Idle state, then informations are related to the 213 | ; last request the process has served. Otherwise informations are related to 214 | ; the current request being served. 215 | ; Example output: 216 | ; ************************ 217 | ; pid: 31330 218 | ; state: Running 219 | ; start time: 01/Jul/2011:17:53:49 +0200 220 | ; start since: 63087 221 | ; requests: 12808 222 | ; request duration: 1250261 223 | ; request method: GET 224 | ; request URI: /test_mem.php?N=10000 225 | ; content length: 0 226 | ; user: - 227 | ; script: /home/fat/web/docs/php/test_mem.php 228 | ; last request cpu: 0.00 229 | ; last request memory: 0 230 | ; 231 | ; Note: There is a real-time FPM status monitoring sample web page available 232 | ; It's available in: /usr/local/share/php/fpm/status.html 233 | ; 234 | ; Note: The value must start with a leading slash (/). The value can be 235 | ; anything, but it may not be a good idea to use the .php extension or it 236 | ; may conflict with a real PHP file. 237 | ; Default Value: not set 238 | ;pm.status_path = /status 239 | 240 | ; The ping URI to call the monitoring page of FPM. If this value is not set, no 241 | ; URI will be recognized as a ping page. This could be used to test from outside 242 | ; that FPM is alive and responding, or to 243 | ; - create a graph of FPM availability (rrd or such); 244 | ; - remove a server from a group if it is not responding (load balancing); 245 | ; - trigger alerts for the operating team (24/7). 246 | ; Note: The value must start with a leading slash (/). The value can be 247 | ; anything, but it may not be a good idea to use the .php extension or it 248 | ; may conflict with a real PHP file. 249 | ; Default Value: not set 250 | ;ping.path = /ping 251 | 252 | ; This directive may be used to customize the response of a ping request. The 253 | ; response is formatted as text/plain with a 200 response code. 254 | ; Default Value: pong 255 | ;ping.response = pong 256 | 257 | ; The access log file 258 | ; Default: not set 259 | ;access.log = log/$pool.access.log 260 | 261 | ; The access log format. 262 | ; The following syntax is allowed 263 | ; %%: the '%' character 264 | ; %C: %CPU used by the request 265 | ; it can accept the following format: 266 | ; - %{user}C for user CPU only 267 | ; - %{system}C for system CPU only 268 | ; - %{total}C for user + system CPU (default) 269 | ; %d: time taken to serve the request 270 | ; it can accept the following format: 271 | ; - %{seconds}d (default) 272 | ; - %{miliseconds}d 273 | ; - %{mili}d 274 | ; - %{microseconds}d 275 | ; - %{micro}d 276 | ; %e: an environment variable (same as $_ENV or $_SERVER) 277 | ; it must be associated with embraces to specify the name of the env 278 | ; variable. Some exemples: 279 | ; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e 280 | ; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e 281 | ; %f: script filename 282 | ; %l: content-length of the request (for POST request only) 283 | ; %m: request method 284 | ; %M: peak of memory allocated by PHP 285 | ; it can accept the following format: 286 | ; - %{bytes}M (default) 287 | ; - %{kilobytes}M 288 | ; - %{kilo}M 289 | ; - %{megabytes}M 290 | ; - %{mega}M 291 | ; %n: pool name 292 | ; %o: output header 293 | ; it must be associated with embraces to specify the name of the header: 294 | ; - %{Content-Type}o 295 | ; - %{X-Powered-By}o 296 | ; - %{Transfert-Encoding}o 297 | ; - .... 298 | ; %p: PID of the child that serviced the request 299 | ; %P: PID of the parent of the child that serviced the request 300 | ; %q: the query string 301 | ; %Q: the '?' character if query string exists 302 | ; %r: the request URI (without the query string, see %q and %Q) 303 | ; %R: remote IP address 304 | ; %s: status (response code) 305 | ; %t: server time the request was received 306 | ; it can accept a strftime(3) format: 307 | ; %d/%b/%Y:%H:%M:%S %z (default) 308 | ; The strftime(3) format must be encapsuled in a %{}t tag 309 | ; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t 310 | ; %T: time the log has been written (the request has finished) 311 | ; it can accept a strftime(3) format: 312 | ; %d/%b/%Y:%H:%M:%S %z (default) 313 | ; The strftime(3) format must be encapsuled in a %{}t tag 314 | ; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t 315 | ; %u: remote user 316 | ; 317 | ; Default: "%R - %u %t \"%m %r\" %s" 318 | ;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" 319 | 320 | ; The log file for slow requests 321 | ; Default Value: not set 322 | ; Note: slowlog is mandatory if request_slowlog_timeout is set 323 | ;slowlog = log/$pool.log.slow 324 | 325 | ; The timeout for serving a single request after which a PHP backtrace will be 326 | ; dumped to the 'slowlog' file. A value of '0s' means 'off'. 327 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) 328 | ; Default Value: 0 329 | ;request_slowlog_timeout = 0 330 | 331 | ; Depth of slow log stack trace. 332 | ; Default Value: 20 333 | ;request_slowlog_trace_depth = 20 334 | 335 | ; The timeout for serving a single request after which the worker process will 336 | ; be killed. This option should be used when the 'max_execution_time' ini option 337 | ; does not stop script execution for some reason. A value of '0' means 'off'. 338 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) 339 | ; Default Value: 0 340 | ;request_terminate_timeout = 0 341 | 342 | ; Set open file descriptor rlimit. 343 | ; Default Value: system defined value 344 | ;rlimit_files = 1024 345 | 346 | ; Set max core size rlimit. 347 | ; Possible Values: 'unlimited' or an integer greater or equal to 0 348 | ; Default Value: system defined value 349 | ;rlimit_core = 0 350 | 351 | ; Chroot to this directory at the start. This value must be defined as an 352 | ; absolute path. When this value is not set, chroot is not used. 353 | ; Note: you can prefix with '$prefix' to chroot to the pool prefix or one 354 | ; of its subdirectories. If the pool prefix is not set, the global prefix 355 | ; will be used instead. 356 | ; Note: chrooting is a great security feature and should be used whenever 357 | ; possible. However, all PHP paths will be relative to the chroot 358 | ; (error_log, sessions.save_path, ...). 359 | ; Default Value: not set 360 | ;chroot = 361 | 362 | ; Chdir to this directory at the start. 363 | ; Note: relative path can be used. 364 | ; Default Value: current directory or / when chroot 365 | ;chdir = /var/www 366 | 367 | ; Redirect worker stdout and stderr into main error log. If not set, stdout and 368 | ; stderr will be redirected to /dev/null according to FastCGI specs. 369 | ; Note: on highloaded environement, this can cause some delay in the page 370 | ; process time (several ms). 371 | ; Default Value: no 372 | ;catch_workers_output = yes 373 | 374 | ; Clear environment in FPM workers 375 | ; Prevents arbitrary environment variables from reaching FPM worker processes 376 | ; by clearing the environment in workers before env vars specified in this 377 | ; pool configuration are added. 378 | ; Setting to "no" will make all environment variables available to PHP code 379 | ; via getenv(), $_ENV and $_SERVER. 380 | ; Default Value: yes 381 | ;clear_env = no 382 | 383 | ; Limits the extensions of the main script FPM will allow to parse. This can 384 | ; prevent configuration mistakes on the web server side. You should only limit 385 | ; FPM to .php extensions to prevent malicious users to use other extensions to 386 | ; execute php code. 387 | ; Note: set an empty value to allow all extensions. 388 | ; Default Value: .php 389 | ;security.limit_extensions = .php .php3 .php4 .php5 .php7 390 | 391 | ; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from 392 | ; the current environment. 393 | ; Default Value: clean env 394 | ;env[HOSTNAME] = $HOSTNAME 395 | ;env[PATH] = /usr/local/bin:/usr/bin:/bin 396 | ;env[TMP] = /tmp 397 | ;env[TMPDIR] = /tmp 398 | ;env[TEMP] = /tmp 399 | 400 | ; Additional php.ini defines, specific to this pool of workers. These settings 401 | ; overwrite the values previously defined in the php.ini. The directives are the 402 | ; same as the PHP SAPI: 403 | ; php_value/php_flag - you can set classic ini defines which can 404 | ; be overwritten from PHP call 'ini_set'. 405 | ; php_admin_value/php_admin_flag - these directives won't be overwritten by 406 | ; PHP call 'ini_set' 407 | ; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. 408 | 409 | ; Defining 'extension' will load the corresponding shared extension from 410 | ; extension_dir. Defining 'disable_functions' or 'disable_classes' will not 411 | ; overwrite previously defined php.ini values, but will append the new value 412 | ; instead. 413 | 414 | ; Note: path INI options can be relative and will be expanded with the prefix 415 | ; (pool, global or /usr/local) 416 | 417 | ; Default Value: nothing is defined by default except the values in php.ini and 418 | ; specified at startup with the -d argument 419 | ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com 420 | ;php_flag[display_errors] = off 421 | ;php_admin_value[error_log] = /var/log/fpm-php.www.log 422 | ;php_admin_flag[log_errors] = on 423 | ;php_admin_value[memory_limit] = 32M 424 | -------------------------------------------------------------------------------- /commands/start.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "docker-symfony/util" 5 | "fmt" 6 | "github.com/symfony-cli/console" 7 | "log" 8 | "os" 9 | "os/user" 10 | "runtime" 11 | "strings" 12 | ) 13 | 14 | var envFile = util.GetCurrentDir() + "/.env" 15 | var envDistFile = envFile + ".dist" 16 | 17 | var envSecretFile = envFile + ".secret" 18 | 19 | var startCmd = &console.Command{ 20 | Category: "d4d", 21 | Name: "start", 22 | Aliases: []*console.Alias{{Name: "start"}}, 23 | Usage: "", 24 | Action: func(c *console.Context) error { 25 | doChecks() 26 | doBuildNginxConf() 27 | doBuildMySQLConf() 28 | doBuild() 29 | doBeforeStart() 30 | //start() 31 | 32 | return nil 33 | }, 34 | } 35 | 36 | func doChecks() { 37 | if !util.IsCommandExist("docker") { 38 | fmt.Println("Docker not found. Please install it via https://docs.docker.com/install/") 39 | os.Exit(1) 40 | } 41 | 42 | if !util.FileExists(envFile) { 43 | if util.FileExists(envDistFile) { 44 | util.Copy(envDistFile, envFile) 45 | 46 | fileData, err := os.ReadFile(envSecretFile) 47 | if err != nil { 48 | os.Exit(1) 49 | } 50 | 51 | fileString := string(fileData) 52 | util.AppendFile(envFile, fileString) 53 | } else { 54 | fmt.Sprintf("The %s file does not exist. Project setup will not work.", envDistFile) 55 | os.Exit(1) 56 | } 57 | } 58 | 59 | // Always validate user id and group id before start using .env file 60 | if runtime.GOOS != "darwin" { 61 | util.Sed("USER_ID=.*", fmt.Sprintf("USER_ID=%d", os.Getuid()), envFile) 62 | util.Sed("GROUP_ID=.*", fmt.Sprintf("GROUP_ID=%d", os.Getgid()), envFile) 63 | } else { 64 | util.Sed("USER_ID=.*", fmt.Sprintf("USER_ID=%d", os.Getuid()), envFile) 65 | util.Sed("GROUP_ID=.*", fmt.Sprintf("GROUP_ID=%d", os.Getuid()), envFile) 66 | } 67 | util.Sed("MYSQL_ROOT_PASSWORD=root", fmt.Sprintf("MYSQL_ROOT_PASSWORD=%s", util.GeneratePassword(20)), envSecretFile) 68 | util.Sed("MYSQL_PASSWORD=db_password", fmt.Sprintf("MYSQL_PASSWORD=%s", util.GeneratePassword(20)), envSecretFile) 69 | util.Sed("MONGODB_ROOT_PASSWORD=root", fmt.Sprintf("MONGODB_ROOT_PASSWORD=%s", util.GeneratePassword(20)), envSecretFile) 70 | util.Sed("MONGODB_PASSWORD=db_password", fmt.Sprintf("MONGODB_PASSWORD=%s", util.GeneratePassword(20)), envSecretFile) 71 | 72 | fileData, err := os.ReadFile(envFile) 73 | if err != nil { 74 | os.Exit(1) 75 | } 76 | 77 | if !strings.Contains(string(fileData), "# .env.secret") { 78 | fileData, err := os.ReadFile(envSecretFile) 79 | if err != nil { 80 | os.Exit(1) 81 | } 82 | 83 | fileString := string(fileData) 84 | util.AppendFile(envFile, fileString) 85 | } 86 | 87 | util.LoadEnvFile(envFile) 88 | 89 | sshKeyPath := os.Getenv("HOME") + "/.ssh" 90 | 91 | // Ensure all folders exists 92 | var dirs = []string{ 93 | os.Getenv("PROJECT_PATH"), 94 | os.Getenv("SF_COMMUNITY_PATH"), 95 | os.Getenv("SF_COMMUNITY_PATH") + "/symfony", 96 | os.Getenv("SF_COMMUNITY_PATH") + "/recipes", 97 | os.Getenv("SF_COMMUNITY_PATH") + "/symfony-docs", 98 | "./.composer", 99 | "./.composer/cache", 100 | "./scripts/", 101 | sshKeyPath, 102 | os.Getenv("MYSQL_DUMP_PATH"), 103 | } 104 | util.Mkdir(dirs, 0755) 105 | 106 | sshPrivateKey := sshKeyPath + "/id_rsa_test" 107 | sshPublicKey := sshPrivateKey + ".pub" 108 | if !util.FileExists(sshPrivateKey) { 109 | pubKey, privKey, _ := util.MakeSSHKeyPair() 110 | if pubKey != "" && privKey != "" { 111 | f, _ := os.Create(sshPublicKey) 112 | 113 | // get current user 114 | user, err := user.Current() 115 | if err != nil { 116 | log.Fatalf(err.Error()) 117 | } 118 | 119 | f.WriteString(fmt.Sprintf("%s %s@d4d.lt\n", strings.Replace(pubKey, "\n", "", 1), user.Username)) 120 | 121 | f2, _ := os.Create(sshPrivateKey) 122 | f2.WriteString(privKey) 123 | } 124 | } 125 | 126 | if !util.FileExists(sshKeyPath + "/known_hosts") { 127 | os.Create(sshKeyPath + "/known_hosts") 128 | } 129 | 130 | os.MkdirAll(os.Getenv("NGINX_SSL_PATH"), 0755) 131 | os.Mkdir(os.Getenv("NGINX_LOG_PATH"), 0755) 132 | os.Mkdir(os.Getenv("MYSQL_DATA_PATH"), 0755) 133 | os.Mkdir(os.Getenv("USER_CONFIG_PATH"), 0755) 134 | os.Mkdir(os.Getenv("MONGODB_LOG_PATH"), 0755) 135 | os.Mkdir(os.Getenv("MONGODB_DATA_PATH"), 0755) 136 | 137 | // Create a file if it does not exist 138 | util.CreateFileIfNotExists(os.Getenv("USER_CONFIG_PATH") + "/.bash_history") 139 | util.CreateFileIfNotExists(os.Getenv("USER_CONFIG_PATH") + "/.gitconfig") 140 | util.CreateFileIfNotExists(os.Getenv("USER_CONFIG_PATH") + "/.gitignore") 141 | 142 | if !util.FileExists(os.Getenv("USER_CONFIG_PATH") + "/.my.cnf") { 143 | data := fmt.Sprintf("[client]\nuser=%s\npassword=%s\n", os.Getenv("MYSQL_USER"), os.Getenv("MYSQL_PASSWORD")) 144 | util.AppendFile(os.Getenv("USER_CONFIG_PATH")+"/.my.cnf", data) 145 | } 146 | 147 | if os.Getenv("NGINX_SSL") == "yes" { 148 | if !util.FileExists("user/nginx/ssl/d4d.pem") || !util.FileExists("user/nginx/ssl/d4d-key.pem") { 149 | // ./d4d mkcert ssl 150 | } 151 | } 152 | 153 | doNginxBuild() 154 | doPhpBuild() 155 | doPhpMyAdminBuild() 156 | 157 | // phpMyAdmin configuration 158 | pmaAuthType := "cookie" 159 | pmaMySQLUser := "" 160 | pmaMySQLPassword := "" 161 | 162 | if os.Getenv("PMA_AUTO_LOGIN") == "yes" { 163 | pmaAuthType = "config" 164 | pmaMySQLUser = "root" 165 | pmaMySQLPassword = os.Getenv("MYSQL_ROOT_PASSWORD") 166 | 167 | if os.Getenv("PMA_AUTO_LOGIN") == "no" { 168 | pmaMySQLUser = os.Getenv("MYSQL_USER") 169 | pmaMySQLPassword = os.Getenv("MYSQL_PASSWORD") 170 | } 171 | } 172 | 173 | util.Copy("config/phpmyadmin/config.user.inc.php.d4d", "config/phpmyadmin/config.user.inc.php") 174 | util.Sed("__AUTH_TYPE__", pmaAuthType, "config/phpmyadmin/config.user.inc.php") 175 | util.Sed("__MYSQL_USER__", pmaMySQLUser, "config/phpmyadmin/config.user.inc.php") 176 | util.Sed("__MYSQL_PASSWORD__", pmaMySQLPassword, "config/phpmyadmin/config.user.inc.php") 177 | } 178 | 179 | func doNginxBuild() { 180 | util.Copy("config/nginx/Dockerfile.build", "config/nginx/Dockerfile") 181 | 182 | util.Sed("__DEBIAN_VERSION__", os.Getenv("DEBIAN_VERSION"), "config/nginx/Dockerfile") 183 | 184 | if os.Getenv("NGINX_SSL") == "yes" { 185 | os.Mkdir("config/nginx/ssl", 0755) 186 | 187 | util.Copy("user/nginx/ssl/d4d.pem", "config/nginx/ssl/d4d.pem") 188 | util.Copy("user/nginx/ssl/d4d-key.pem", "config/nginx/ssl/d4d-key.pem") 189 | 190 | util.Sed("__D4D_SSL__", "COPY [\"ssl/d4d.pem\", \"ssl/d4d-key.pem\", \"/etc/nginx/ssl/\"]", "config/nginx/Dockerfile") 191 | 192 | } else { 193 | util.Sed("__D4D_SSL__", "", "config/nginx/Dockerfile") 194 | } 195 | } 196 | 197 | func doPhpBuild() { 198 | util.Copy("config/php/Dockerfile.build", "config/php/Dockerfile") 199 | 200 | packageList := []string{"gnupg2", "openssl", "git", "unzip", "libzip-dev", "nano", "libpng-dev", "libmagickwand-dev", "curl", "openssh-client", "less", "inkscape", "cron", "exiftool", "libicu-dev", "libmcrypt-dev", "libc-client-dev", "libkrb5-dev", "libssl-dev", "libxslt1-dev", "bash-completion"} 201 | peclInstall := []string{} 202 | phpExtConfigure := []string{} 203 | phpExtInstall := []string{"pdo", "pdo_mysql", "opcache", "zip", "mysqli", "exif", "bcmath", "calendar", "intl", "soap", "sockets", "xsl"} 204 | phpExtEnable := []string{"mysqli", "calendar", "exif", "bcmath"} 205 | npmInstallGlobal := []string{} 206 | 207 | phpVersion := os.Getenv("PHP_VERSION") 208 | 209 | if phpVersion == "7.1" { 210 | phpExtInstall = append(phpExtInstall, "mcrypt") 211 | phpExtEnable = append(phpExtEnable, "mcrypt") 212 | } 213 | 214 | if phpVersion >= "7.1" && phpVersion <= "7.3" { 215 | phpExtConfigure = append(phpExtConfigure, "docker-php-ext-configure zip --with-libzip") 216 | } 217 | 218 | if phpVersion >= "7.4" && phpVersion <= "8.4" { 219 | phpExtConfigure = append(phpExtConfigure, "docker-php-ext-configure zip") 220 | } 221 | 222 | phpExtConfigure = append(phpExtConfigure, "&& docker-php-ext-configure intl") 223 | 224 | if os.Getenv("PHP_IMAGICK") == "yes" { 225 | peclInstall = append(peclInstall, "imagick") 226 | phpExtEnable = append(phpExtEnable, "imagick") 227 | } 228 | 229 | if os.Getenv("PHP_GD") == "yes" { 230 | supportedVersions := []string{"7.4", "8.0", "8.1", "8.2", "8.3", "8.4"} 231 | gdConfigure := "&& docker-php-ext-configure gd" 232 | if !util.Contains(supportedVersions, phpVersion) { 233 | gdConfigure += " --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/" 234 | } else { 235 | gdConfigure += " --with-freetype --with-jpeg" 236 | } 237 | phpExtConfigure = append(phpExtConfigure, gdConfigure) 238 | phpExtInstall = append(phpExtInstall, "gd") 239 | } 240 | 241 | if os.Getenv("RABBITMQ") == "yes" { 242 | packageList = append(packageList, "librabbitmq-dev", "librabbitmq4") 243 | 244 | if phpVersion >= "7.1" && phpVersion <= "7.3" { 245 | peclInstall = append(peclInstall, "amqp-1.11.0") 246 | } 247 | 248 | if phpVersion >= "7.4" && phpVersion <= "8.4" { 249 | peclInstall = append(peclInstall, "amqp-2.1.2") 250 | } 251 | 252 | util.Sed("__RABBIT_MQ__", "&& echo 'extension=amqp.so' >> $$PHP_INI_DIR/conf.d/docker-php-ext-amqp.ini"+" \\", "config/php/Dockerfile") 253 | } else { 254 | util.Sed("__RABBIT_MQ__", "", "config/php/Dockerfile") 255 | } 256 | 257 | if os.Getenv("MONGODB") == "yes" { 258 | if phpVersion == "7.1" { 259 | peclInstall = append(peclInstall, "mongodb-1.11.1") 260 | util.Sed("__MONGODB__", "&& echo 'extension=mongodb.so' >> $$PHP_INI_DIR/conf.d/docker-php-ext-mongodb.ini"+" \\", "config/php/Dockerfile") 261 | } 262 | 263 | if phpVersion >= "7.2" && phpVersion <= "7.3" { 264 | peclInstall = append(peclInstall, "mongodb-1.16.2") 265 | } 266 | 267 | if phpVersion >= "7.4" && phpVersion <= "8.4" { 268 | peclInstall = append(peclInstall, "mongodb-1.20.1") 269 | } 270 | 271 | if phpVersion != "7.2" { 272 | util.Sed("__MONGODB__", "&& echo 'extension=mongodb.so' >> $$PHP_INI_DIR/conf.d/docker-php-ext-mongodb.ini"+" \\", "config/php/Dockerfile") 273 | } else { 274 | util.Sed("__MONGODB__", "&& echo 'extension=mongodb' >> $$PHP_INI_DIR/conf.d/docker-php-ext-mongodb.ini"+" \\", "config/php/Dockerfile") 275 | } 276 | } else { 277 | util.Sed("__MONGODB__", "", "config/php/Dockerfile") 278 | } 279 | 280 | if os.Getenv("PHP_IMAP") == "yes" { 281 | phpExtConfigure = append(phpExtConfigure, "&& docker-php-ext-configure imap --with-kerberos --with-imap-ssl") 282 | 283 | phpExtInstall = append(phpExtInstall, "imap") 284 | } 285 | 286 | if os.Getenv("REDIS") == "yes" { 287 | if phpVersion >= "7.1" && phpVersion <= "7.3" { 288 | peclInstall = append(peclInstall, "redis-5.3.7") 289 | } 290 | 291 | if phpVersion >= "7.4" && phpVersion <= "8.4" { 292 | peclInstall = append(peclInstall, "redis-6.1.0") 293 | } 294 | 295 | phpExtEnable = append(phpExtEnable, "redis") 296 | } 297 | 298 | if os.Getenv("SUPERVISOR") == "yes" { 299 | packageList = append(packageList, "supervisor") 300 | } 301 | 302 | if os.Getenv("XDEBUG") == "yes" { 303 | if phpVersion == "7.1" { 304 | peclInstall = append(peclInstall, "xdebug-2.9.8") 305 | } 306 | 307 | if phpVersion >= "7.2" && phpVersion <= "7.4" { 308 | peclInstall = append(peclInstall, "xdebug-3.1.6") 309 | } 310 | 311 | if phpVersion >= "8.0" && phpVersion <= "8.4" { 312 | peclInstall = append(peclInstall, "xdebug-3.4.0") 313 | } 314 | 315 | util.Copy("config/php/conf.d/xdebug.d4d", "config/php/conf.d/xdebug.ini") 316 | 317 | util.Sed("__PHP_XDEBUG_CLIENT_PORT__", os.Getenv("XDEBUG_CLIENT_PORT"), "config/php/conf.d/xdebug.ini") 318 | util.Sed("__PHP_XDEBUG_START_WITH_REQUEST__", os.Getenv("XDEBUG_START_WITH_REQUEST"), "config/php/conf.d/xdebug.ini") 319 | 320 | if os.Getenv("XDEBUG_REMOTE_HOST") != "" { 321 | util.AppendFile("config/php/conf.d/xdebug.ini", fmt.Sprintf("\nxdebug.remote_host = %s", os.Getenv("XDEBUG_REMOTE_HOST"))) 322 | } 323 | if os.Getenv("XDEBUG_REMOTE_CONNECT_BACK") != "" { 324 | util.AppendFile("config/php/conf.d/xdebug.ini", fmt.Sprintf("\nxdebug.remote_connect_back = %s", os.Getenv("XDEBUG_REMOTE_CONNECT_BACK"))) 325 | } 326 | 327 | if phpVersion >= "7.1" && phpVersion <= "8.4" { 328 | util.Sed("__XDEBUG__", "&& echo 'zend_extension=xdebug.so' >> $$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"+" \\", "config/php/Dockerfile") 329 | } else { 330 | util.Sed("__XDEBUG__", "&& echo 'extension=xdebug.so' >> $$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"+" \\", "config/php/Dockerfile") 331 | } 332 | } else { 333 | util.Sed("__XDEBUG__", "", "config/php/Dockerfile") 334 | } 335 | 336 | util.Sed(" __CURL_INSECURE__", "", "config/php/Dockerfile") 337 | 338 | if os.Getenv("SF_CLI") == "yes" { 339 | packageList = append(packageList, "symfony-cli") 340 | } 341 | 342 | npmInstallGlobal = append(npmInstallGlobal, "npm", "grunt-cli", "yargs", "async", "sass", "gulp", "requirejs", "pm2", "uglify-js", "typescript", "eslint") 343 | 344 | if os.Getenv("YARN") == "yes" { 345 | util.Sed("__YARN__", "&& apt-get remove -y cmdtest && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /etc/apt/trusted.gpg.d/yarn.gpg >/dev/null && echo \"deb https://dl.yarnpkg.com/debian/ stable main\" | tee /etc/apt/sources.list.d/yarn.list && apt-get update && apt-get install -y yarn", "config/php/Dockerfile") 346 | } else { 347 | util.Sed("__YARN__", "", "config/php/Dockerfile") 348 | } 349 | 350 | if os.Getenv("NODEJS") == "yes" { 351 | util.Sed("__NODEJS__", "&& mkdir -p /var/www/.npm && mkdir -p /var/www/html && printf '{\"name\": \"d4d\", \"version\": \"1.0.0\"}' > /var/www/html/package.json && chown -R $${USER_ID}:$${GROUP_ID} /var/www/.npm && chown -R $${USER_ID}:$${GROUP_ID} /var/www/html && mkdir -p /etc/apt/keyrings && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && NODE_MAJOR=$${NODE_JS_VERSION} && echo \"deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$${NODE_MAJOR}.x nodistro main\" | tee /etc/apt/sources.list.d/nodesource.list && apt-get update && apt-get install -y nodejs && npm install --location=global __NPM_INSTALL_GLOBAL__ \\\n ", "config/php/Dockerfile") 352 | } else { 353 | util.Sed("__NODEJS__", "", "config/php/Dockerfile") 354 | } 355 | 356 | if os.Getenv("WKHTMLTOPDF") == "yes" { 357 | if os.Getenv("WKHTMLTOPDF_VERSION") == "0.12.3" { 358 | util.Sed("__WKHTMLTOPDF__", "&& curl -o wkhtmltox-${WKHTMLTOPDF_VERSION}_linux-generic-amd64.tar.xz -sL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/${WKHTMLTOPDF_VERSION}/wkhtmltox-${WKHTMLTOPDF_VERSION}_linux-generic-amd64.tar.xz && echo '9066ab2c7b2035c6eaa043d31aeb7260191e6c88 wkhtmltox-${WKHTMLTOPDF_VERSION}_linux-generic-amd64.tar.xz' | sha1sum -c - && tar -xvf wkhtmltox-${WKHTMLTOPDF_VERSION}_linux-generic-amd64.tar.xz && cp wkhtmltox/lib/* /usr/lib/ && cp wkhtmltox/bin/* /usr/bin/ && cp -r wkhtmltox/share/man/man1 /usr/share/man/ && chmod a+x /usr/bin/wkhtmltopdf && chmod a+x /usr/bin/wkhtmltoimage", "config/php/Dockerfile") 359 | } 360 | if os.Getenv("WKHTMLTOPDF_VERSION") == "0.12.4" { 361 | util.Sed("", "&& curl -o wkhtmltox-${WKHTMLTOPDF_VERSION}_linux-generic-amd64.tar.xz -sL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/${WKHTMLTOPDF_VERSION}/wkhtmltox-${WKHTMLTOPDF_VERSION}_linux-generic-amd64.tar.xz && echo '3f923f425d345940089e44c1466f6408b9619562 wkhtmltox-${WKHTMLTOPDF_VERSION}_linux-generic-amd64.tar.xz' | sha1sum -c - && tar -xvf wkhtmltox-${WKHTMLTOPDF_VERSION}_linux-generic-amd64.tar.xz && cp wkhtmltox/lib/* /usr/lib/ && cp wkhtmltox/bin/* /usr/bin/ && cp -r wkhtmltox/share/man/man1 /usr/share/man/ && chmod a+x /usr/bin/wkhtmltopdf && chmod a+x /usr/bin/wkhtmltoimage", "config/php/Dockerfile") 362 | } 363 | if os.Getenv("WKHTMLTOPDF_VERSION") == "0.12.5" { 364 | util.Sed("", "&& curl -o /tmp/wkhtmltox_${WKHTMLTOPDF_VERSION}.`echo $(lsb_release -cs)`_amd64.deb -sL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/${WKHTMLTOPDF_VERSION}/wkhtmltox_${WKHTMLTOPDF_VERSION}-1.`echo $(lsb_release -cs)`_amd64.deb && apt-get --assume-yes install /tmp/wkhtmltox_${WKHTMLTOPDF_VERSION}.`echo $(lsb_release -cs)`_amd64.deb && rm /tmp/wkhtmltox_${WKHTMLTOPDF_VERSION}.`echo $(lsb_release -cs)`_amd64.deb && ln -s /usr/local/bin/wkhtmltopdf /usr/bin/wkhtmltopdf && ln -s /usr/local/bin/wkhtmltoimage /usr/bin/wkhtmltoimage", "config/php/Dockerfile") 365 | } 366 | if os.Getenv("WKHTMLTOPDF_VERSION") == "0.12.6" { 367 | util.Sed("", "&& curl -o /tmp/wkhtmltox_${WKHTMLTOPDF_VERSION}.`echo $(lsb_release -cs)`_amd64.deb -sL https://github.com/wkhtmltopdf/packaging/releases/download/${WKHTMLTOPDF_VERSION}-1/wkhtmltox_${WKHTMLTOPDF_VERSION}-1.`echo $(lsb_release -cs)`_amd64.deb && apt-get --assume-yes install /tmp/wkhtmltox_${WKHTMLTOPDF_VERSION}.`echo $(lsb_release -cs)`_amd64.deb && rm /tmp/wkhtmltox_${WKHTMLTOPDF_VERSION}.`echo $(lsb_release -cs)`_amd64.deb && ln -s /usr/local/bin/wkhtmltopdf /usr/bin/wkhtmltopdf && ln -s /usr/local/bin/wkhtmltoimage /usr/bin/wkhtmltoimage", "config/php/Dockerfile") 368 | } 369 | } else { 370 | util.Sed("__WKHTMLTOPDF__", "", "config/php/Dockerfile") 371 | } 372 | 373 | if os.Getenv("BLACKFIRE") == "yes" { 374 | util.Sed("__BLACKFIRE__", "&& curl -sS https://packages.blackfire.io/gpg.key | apt-key add - && echo \"deb http://packages.blackfire.io/debian any main\" | tee /etc/apt/sources.list.d/blackfire.list && apt-get update && apt-get install -y blackfire blackfire-php", "config/php/Dockerfile") 375 | } else { 376 | util.Sed("__BLACKFIRE__ \\\\", "", "config/php/Dockerfile") 377 | } 378 | 379 | util.Sed("__PACKAGE_LIST__", strings.Join(packageList, " "), "config/php/Dockerfile") 380 | util.Sed("__PHP_EXT_CONFIGURE__", strings.Join(phpExtConfigure, " ")+" \\", "config/php/Dockerfile") 381 | util.Sed("__PHP_EXT_INSTALL__", "&& docker-php-ext-install -j$(nproc) "+strings.Join(phpExtInstall, " ")+" \\", "config/php/Dockerfile") 382 | 383 | if len(peclInstall) > 0 { 384 | util.Sed("__PECL_INSTALL__", "&& pecl install "+strings.Join(peclInstall, " ")+" \\", "config/php/Dockerfile") 385 | } else { 386 | util.Sed("__PECL_INSTALL__", "", "config/php/Dockerfile") 387 | } 388 | 389 | if len(phpExtEnable) > 0 { 390 | util.Sed("__PHP_EXT_ENABLE__", "&& docker-php-ext-enable "+strings.Join(phpExtEnable, " ")+" \\", "config/php/Dockerfile") 391 | } else { 392 | util.Sed("__PHP_EXT_ENABLE__", "", "config/php/Dockerfile") 393 | } 394 | 395 | util.Sed("__NPM_INSTALL_GLOBAL__", strings.Join(npmInstallGlobal, " "), "config/php/Dockerfile") 396 | util.Sed("__CLEANUP__", "&& apt-get clean && rm -rf /var/lib/apt/lists/*", "config/php/Dockerfile") 397 | 398 | if os.Getenv("SF_CLI") == "yes" { 399 | util.Sed("__SYMFONY_CLI__", "echo \"deb [trusted=yes] https://repo.symfony.com/apt/ /\" | tee /etc/apt/sources.list.d/symfony-cli.list && \\", "config/php/Dockerfile") 400 | } else { 401 | util.Sed("__SYMFONY_CLI__", "\\", "config/php/Dockerfile") 402 | } 403 | 404 | util.Sed(" \n", "", "config/php/Dockerfile") 405 | } 406 | 407 | func doPhpMyAdminBuild() { 408 | util.Copy("config/phpmyadmin/Dockerfile.build", "config/phpmyadmin/Dockerfile") 409 | 410 | if runtime.GOOS != "darwin" { 411 | util.Sed("__PHP_MY_ADMIN__", "phpmyadmin/phpmyadmin", "config/phpmyadmin/Dockerfile") 412 | } else { 413 | util.Sed("__PHP_MY_ADMIN__", "arm64v8/phpmyadmin", "config/phpmyadmin/Dockerfile") 414 | } 415 | } 416 | 417 | func remove(haystack []string, needle string) []string { 418 | for index, value := range haystack { 419 | if value == needle { 420 | return append(haystack[:index], haystack[index+1:]...) 421 | } 422 | } 423 | return haystack 424 | } 425 | 426 | func doBuildNginxConf() { 427 | projectConfFile := "config/nginx/project.conf" 428 | 429 | if os.Getenv("NGINX_SSL") == "yes" { 430 | util.Copy("config/nginx/project-ssl.conf.default", projectConfFile) 431 | } else { 432 | util.Copy("config/nginx/project.conf.default", projectConfFile) 433 | } 434 | 435 | util.Sed("__INCLUDE__", "/etc/nginx/d4d/sf.conf", projectConfFile) 436 | util.Sed("__PHP_MAX_EXECUTION_TIME__", os.Getenv("PHP_MAX_EXECUTION_TIME"), projectConfFile) 437 | util.Sed("__NGINX_FASTCGI_BUFFERS__", os.Getenv("NGINX_FASTCGI_BUFFERS"), projectConfFile) 438 | util.Sed("__NGINX_FASTCGI_BUFFER_SIZE__", os.Getenv("NGINX_FASTCGI_BUFFER_SIZE"), projectConfFile) 439 | util.Sed("__PHP_UPLOAD_MAX_FILESIZE__", os.Getenv("PHP_UPLOAD_MAX_FILESIZE"), projectConfFile) 440 | 441 | util.Copy("config/nginx/d4d/pwa.conf.default", "config/nginx/d4d/pwa.conf") 442 | util.Sed("__SYMFONY_FRONT_CONTROLLER__", os.Getenv("SYMFONY_FRONT_CONTROLLER"), "config/nginx/d4d/pwa.conf") 443 | 444 | util.Copy("config/nginx/d4d/sf.conf.default", "config/nginx/d4d/sf.conf") 445 | util.Sed("__SYMFONY_FRONT_CONTROLLER__", os.Getenv("SYMFONY_FRONT_CONTROLLER"), "config/nginx/d4d/sf.conf") 446 | 447 | util.Copy("config/nginx/d4d/wp.conf.default", "config/nginx/d4d/wp.conf") 448 | util.Sed("__SYMFONY_FRONT_CONTROLLER__", os.Getenv("SYMFONY_FRONT_CONTROLLER"), "config/nginx/d4d/wp.conf") 449 | 450 | nginxIncludeCache := "" 451 | 452 | if os.Getenv("NGINX_CACHE") == "yes" { 453 | nginxIncludeCache = "include /etc/nginx/d4d/cache.conf;" 454 | } 455 | 456 | util.Sed("__INCLUDE_CACHE__", nginxIncludeCache, projectConfFile) 457 | } 458 | 459 | func doBuildMySQLConf() { 460 | util.Copy("config/mysql/d4d.cnf.d4d", "config/mysql/d4d.cnf") 461 | util.Sed("__MYSQL_MAX_ALLOWED_PACKET__", os.Getenv("MYSQL_MAX_ALLOWED_PACKET"), "config/mysql/d4d.cnf") 462 | util.Sed("__MYSQL_INNODB_LOG_FILE_SIZE__", os.Getenv("MYSQL_INNODB_LOG_FILE_SIZE"), "config/mysql/d4d.cnf") 463 | util.Sed("__MYSQL_WAIT_TIMEOUT__", os.Getenv("MYSQL_WAIT_TIMEOUT"), "config/mysql/d4d.cnf") 464 | util.Sed("__MYSQL_CHARACTER_SET_SERVER__", os.Getenv("MYSQL_CHARACTER_SET_SERVER"), "config/mysql/d4d.cnf") 465 | util.Sed("__MYSQL_COLLATION_SERVER__", os.Getenv("MYSQL_COLLATION_SERVER"), "config/mysql/d4d.cnf") 466 | } 467 | 468 | func doBuild() { 469 | util.Copy("docker/compose.yml", "compose.yaml") 470 | util.AppendFile("compose.yaml", util.FileGetContents("docker/php.yml")) 471 | 472 | if os.Getenv("DOCKER_ENV_PHP") == "yes" { 473 | util.AppendFile("compose.yaml", util.FileGetContents("docker/env/php.yml")) 474 | } 475 | 476 | if os.Getenv("MYSQL") == "yes" { 477 | if os.Getenv("MYSQL_INST") == "mysql" { 478 | util.AppendFile("compose.yaml", util.FileGetContents("docker/mysql.yml")) 479 | } else { 480 | if os.Getenv("MYSQL_INST") == "mariadb" { 481 | util.AppendFile("compose.yaml", util.FileGetContents("docker/mariadb.yml")) 482 | } 483 | } 484 | util.Sed("#php_depends_on", "depends_on:\r\n - mysql", "compose.yaml") 485 | } else { 486 | util.Sed("#php_depends_on", "", "compose.yaml") 487 | } 488 | 489 | if os.Getenv("MAILHOG") == "yes" { 490 | util.AppendFile("compose.yaml", util.FileGetContents("docker/mailhog.yml")) 491 | } 492 | 493 | if os.Getenv("MAILPIT") == "yes" { 494 | util.AppendFile("compose.yaml", util.FileGetContents("docker/mailpit.yml")) 495 | } 496 | 497 | if os.Getenv("PMA") == "yes" && os.Getenv("MYSQL") == "yes" { 498 | util.AppendFile("compose.yaml", util.FileGetContents("docker/phpmyadmin.yml")) 499 | } 500 | 501 | if os.Getenv("REDIS") == "yes" { 502 | util.AppendFile("compose.yaml", util.FileGetContents("docker/redis.yml")) 503 | } 504 | 505 | if os.Getenv("RABBITMQ") == "yes" { 506 | util.AppendFile("compose.yaml", util.FileGetContents("docker/rabbitmq.yml")) 507 | } 508 | 509 | if os.Getenv("ELASTICSEARCH") == "yes" { 510 | util.AppendFile("compose.yaml", util.FileGetContents("docker/elasticsearch.yml")) 511 | } 512 | 513 | if os.Getenv("NGROK") == "yes" { 514 | util.AppendFile("compose.yaml", util.FileGetContents("docker/ngrok.yml")) 515 | } 516 | 517 | if os.Getenv("MONGODB") == "yes" { 518 | util.AppendFile("compose.yaml", util.FileGetContents("docker/mongodb.yml")) 519 | } 520 | 521 | if os.Getenv("ELK") == "yes" { 522 | util.AppendFile("compose.yaml", util.FileGetContents("docker/elk.yml")) 523 | } 524 | 525 | if os.Getenv("EXTERNAL_NETWORK") == "no" || os.Getenv("EXTERNAL_NETWORK") == "yes" { 526 | util.Sed("__NGINX_NETWORKS__", fmt.Sprintf("networks:\n default:\n aliases:\n - %s", os.Getenv("PROJECT_DOMAIN_1")), "compose.yaml") 527 | } 528 | 529 | if os.Getenv("EXTERNAL_NETWORK") == "yes" { 530 | util.AppendFile("compose.yaml", util.FileGetContents("docker/network.yml")) 531 | } 532 | } 533 | 534 | func doBeforeStart() { 535 | envFile := util.GetCurrentDir() + "/.env" 536 | util.LoadEnvFile(envFile) 537 | 538 | if os.Getenv("CLEAN_NGINX_LOGS") == "yes" { 539 | if err := os.Truncate("var/logs/nginx/project_access.log", 0); err != nil { 540 | log.Printf("Failed to truncate: %v", err) 541 | } 542 | } 543 | 544 | if os.Getenv("CLEAN_SF_logs") == "yes" { 545 | os.RemoveAll("project/var/cache") 546 | os.RemoveAll("project/var/log") 547 | } 548 | } 549 | -------------------------------------------------------------------------------- /d4d: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DOCKER_SCRIPT_VER=1.0.18 4 | 5 | OS=`uname` 6 | WORK_DIR=`pwd` 7 | 8 | cd ${WORK_DIR} 9 | 10 | #Added for security 11 | chmod 700 ${WORK_DIR}/docker >/dev/null 2>&1 12 | chmod 700 ${WORK_DIR} >/dev/null 2>&1 13 | 14 | ENV=${WORK_DIR}/.env 15 | ENV_DIST=${WORK_DIR}/.env.dist 16 | 17 | ENV_SECRET=${WORK_DIR}/.env.secret 18 | ENV_SECRET_DIST=${WORK_DIR}/.env.secret.dist 19 | 20 | D4D_ENV=${ENV} 21 | 22 | if [ ! -e ${ENV} ]; then 23 | cp "${ENV_DIST}" "${ENV}" 24 | fi 25 | 26 | if [ ! -e ${ENV_SECRET} ]; then 27 | cp "${ENV_SECRET_DIST}" "${ENV_SECRET}" 28 | fi 29 | 30 | if [ ! -e ${D4D_ENV} ]; then 31 | cp "${D4D_ENV}" "${ENV}" 32 | fi 33 | 34 | # stream editor (sed) 35 | function replace_in_file() { 36 | if [ "$OS" = 'Darwin' ]; then 37 | # for MacOS 38 | sed -i '' "$1" "$2" 39 | else 40 | # for Linux and Windows 41 | sed -i'' "$1" "$2" 42 | fi 43 | } 44 | 45 | function remove_duplicate() { 46 | if [ "$OS" = 'Darwin' ]; then 47 | # for MacOS 48 | sed -i '' '$!N; /^\(.*\)\n\1$/!P; D' "$1" 49 | else 50 | # for Linux and Windows 51 | sed -i'' '$!N; /^\(.*\)\n\1$/!P; D' "$1" 52 | fi 53 | } 54 | 55 | # Emulate ${!variable} 56 | eval_var() { 57 | var=${1} 58 | if [ -z ${var} ]; then 59 | echo "" 60 | else 61 | eval newval="\$${var}" 62 | echo $newval 63 | fi 64 | } 65 | 66 | # Get OS version 67 | DEBIAN_VERSION=/etc/debian_version 68 | if [ "${OS}" = "Darwin" ]; then 69 | OS_VERSION=`uname -r | cut -d- -f1` 70 | elif [ "${OS}" = "FreeBSD" ]; then 71 | OS_VERSION=`uname -r | cut -d- -f1` 72 | OS_FREEBSD_VERSION=`echo ${OS_VER} | cut -d. -f1` 73 | elif [ -e ${DEBIAN_VERSION} ]; then 74 | OS_DEBIAN_VERSION=`grep -m1 -o '^[^\.]*' ${DEBIAN_VERSION}` 75 | else 76 | if [ -s /etc/os-release ]; then 77 | OS_CENTOS_VERSION=`grep -m1 '^VERSION_ID=' /etc/os-release | cut -d. -f1 | cut -d'"' -f2` 78 | else 79 | OS_CENTOS_VERSION=`grep -m1 -o '[0-9]*\.[0-9]*' /etc/redhat-release | cut -d. -f1` 80 | fi 81 | fi 82 | 83 | HIDE_CHANGES=0 84 | 85 | getOpt() { 86 | # $1 is option name 87 | # $2 is default value 88 | 89 | source ${D4D_ENV} 90 | 91 | GET_OPTION="$(eval_var $1)" 92 | if [ "${GET_OPTION}" = "" ]; then 93 | echo "$1=$2" >> ${ENV} 94 | GET_OPTION="${2}" 95 | eval `echo "${1}=${2}"` 96 | fi 97 | 98 | echo ${GET_OPTION} 99 | } 100 | 101 | 102 | getContainerName() { 103 | # $1 is option name 104 | 105 | CURRENT_DIR=`basename ${WORK_DIR}` 106 | if [ "$OS" = 'Darwin' ]; then 107 | # for MacOS 108 | CONTAINER_NAME="${CURRENT_DIR}_${1}_1" 109 | else 110 | # for Linux and Windows 111 | CONTAINER_NAME="${CURRENT_DIR}-${1}-1" 112 | fi 113 | 114 | echo ${CONTAINER_NAME} 115 | } 116 | 117 | getContainerId() { 118 | # $1 is option name 119 | 120 | echo $1 121 | 122 | CURRENT_DIR=`basename ${WORK_DIR}` 123 | CONTAINER_NAME="${CURRENT_DIR}_${1}_1" 124 | CONTAINER_ID=`docker ps -aqf name=^${CONTAINER_NAME}$` 125 | 126 | echo ${CONTAINER_ID} 127 | } 128 | 129 | getContainerIpAddress() { 130 | # $1 is option name 131 | 132 | CONTAINER_NAME=`getContainerName $1` 133 | IP_ADDRESS=`docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${CONTAINER_NAME}` 134 | 135 | echo ${IP_ADDRESS} 136 | } 137 | 138 | ################################################## 139 | # Variables for bolded text 140 | boldon="`tput -Txterm bold`" 141 | boldoff="`tput -Txterm sgr0`" 142 | ################################################## 143 | 144 | setOpt() { 145 | #$1 is option name 146 | #$2 is value 147 | READ_OPTION_NAME="`echo \"$1\" | tr '[:lower:]' '[:upper:]'`" 148 | READ_OPTION_VALUE="`echo \"$2\" | perl -p0 -e 's|@|\\\\@|g'`" 149 | 150 | VAR=`echo ${READ_OPTION_NAME} | tr "[a-z]" "[A-Z]"` 151 | if [ -z "$(eval_var ${VAR}_DEF)" ]; then 152 | echo "${READ_OPTION_NAME} is not a valid option." 153 | EXIT_CODE=50 154 | return 155 | fi 156 | 157 | VALID="no" 158 | for i in $(eval_var ${VAR}_SET); do 159 | if [ "${i}" = "${READ_OPTION_VALUE}" ] || [ "${i}" = "userinput" ]; then 160 | VALID="yes" 161 | break 162 | fi 163 | done 164 | 165 | if [ "${VALID}" = "no" ]; then 166 | echo "${READ_OPTION_VALUE} is not a valid setting for ${READ_OPTION_NAME} option." 167 | EXIT_CODE=51 168 | return 169 | fi 170 | OPT_VALUE="`grep -m1 "^${READ_OPTION_NAME}=" ${ENV} | cut -d= -f2 | perl -p0 -e 's|@|\\\\@|g'`" 171 | perl -pi -e "s#${READ_OPTION_NAME}=${OPT_VALUE}#${READ_OPTION_NAME}=${READ_OPTION_VALUE}#" ${ENV} 172 | if [ "${HIDE_CHANGES}" = "0" ]; then 173 | echo "Changed ${boldon}${READ_OPTION_NAME}${boldoff} option from ${boldon}${OPT_VALUE}${boldoff} to ${boldon}${READ_OPTION_VALUE}${boldoff}" | perl -p0 -e 's|\\\@|\@|g' 174 | fi 175 | } 176 | 177 | ################################################## 178 | 179 | # PHP 180 | PHP_VERSION_SET="5.6 7.0 7.1 7.2 7.3 7.4" 181 | PHP_VERSION_DEF="7.4" 182 | PHP_VERSION_OPT=`getOpt PHP_VERSION ${PHP_VERSION_DEF}` 183 | 184 | # MySQL 185 | MYSQL_VERSION_SET="5.6 5.7 8.0" 186 | MYSQL_VERSION_DEF="5.6" 187 | MYSQL_VERSION_OPT=`getOpt MYSQL_VERSION ${MYSQL_VERSION_DEF}` 188 | 189 | # Debian 190 | DEBIAN_VERSION_SET="stretch buster" 191 | DEBIAN_VERSION_DEF="buster" 192 | DEBIAN_VERSION_OPT=`getOpt DEBIAN_VERSION ${DEBIAN_VERSION_DEF}` 193 | 194 | # Node.js version 195 | NODE_JS_VERSION_SET="4.x 6.x 7.x 8.x 9.x 10.x 11.x 12.x 13.x" 196 | NODE_JS_VERSION_DEF="10.x" 197 | NODE_JS_VERSION_OPT=`getOpt NODE_JS_VERSION ${NODE_JS_VERSION_DEF}` 198 | 199 | # Optional configuration 200 | IONCUBE_SET="yes no" 201 | IONCUBE_DEF="no" 202 | IONCUBE_OPT=`getOpt IONCUBE ${IONCUBE_DEF}` 203 | IONCUBE_DESC="ionCube is a PHP module extension that loads encrypted PHP files and speeds up webpages. It is often required for PHP-based applications." 204 | 205 | XDEBUG_SET="yes no" 206 | XDEBUG_DEF="no" 207 | XDEBUG_OPT=`getOpt XDEBUG ${XDEBUG_DEF}` 208 | XDEBUG_DESC="Xdebug - Debugger and Profiler Tool for PHP" 209 | 210 | YARN_SET="yes no" 211 | YARN_DEF="yes" 212 | YARN_OPT=`getOpt YARN ${YARN_DEF}` 213 | 214 | WKHTMLTOPDF_SET="yes no" 215 | WKHTMLTOPDF_DEF="yes" 216 | WKHTMLTOPDF_OPT=`getOpt WKHTMLTOPDF ${WKHTMLTOPDF_DEF}` 217 | 218 | NGINX_CACHE_SET="yes no" 219 | NGINX_CACHE_DEF="yes" 220 | NGINX_CACHE_OPT=`getOpt NGINX_CACHE ${NGINX_CACHE_DEF}` 221 | 222 | PMA_AUTO_LOGIN_SET="yes no" 223 | PMA_AUTO_LOGIN_DEF="no" 224 | PMA_AUTO_LOGIN_OPT=`getOpt PMA_AUTO_LOGIN ${PMA_AUTO_LOGIN_DEF}` 225 | PMA_AUTO_LOGIN_DESC="phpMyAdmin auto login" 226 | 227 | ################################################## 228 | 229 | # Help sections 230 | HELP_SECTIONS="DOCKER_RUN DOCKER_MYSQL DOCKER_PASSWD D4D_UPDATE DOCKER_D4D" 231 | DOCKER_RUN_SET="install uninstall start stop restart exec logs prune update_images" 232 | DOCKER_RUN_DESC="Docker for Symfony (PHP-FPM - NGINX - MySQL)" 233 | DOCKER_RUN_REQADD="start stop exec logs prune" 234 | START_ADDIT="" 235 | STOP_ADDIT="" 236 | EXEC_ADDIT="" 237 | LOGS_ADDIT="" 238 | 239 | DOCKER_MYSQL_SET="mysql_dump mysql_restore" 240 | DOCKER_MYSQL_DESC="Backup and Restore a MySQL Database" 241 | DOCKER_MYSQL_REQADD="mysql_dump mysql_restore" 242 | DOCKER_MYSQL_DUMP_ADDIT="" 243 | DOCKER_MYSQL_RESTORE_ADDIT="" 244 | 245 | DOCKER_PASSWD_SET="passwd" 246 | DOCKER_PASSWD_DESC="Show password sensitive information" 247 | DOCKER_PASSWD_REQADD="passwd" 248 | PASSWD_ADDIT="show" 249 | 250 | D4D_UPDATE_SET="update_env" 251 | D4D_UPDATE_DESC="Get latest D4D script with or without new packages" 252 | D4D_UPDATE_REQADD="" 253 | 254 | DOCKER_D4D_SET="opt_help set" 255 | DOCKER_D4D_DESC="Docker related options/functions" 256 | DOCKER_D4D_REQADD="opt_help set" 257 | OPT_HELP_ADDIT="(full)" 258 | SET_ADDIT="option_name value" 259 | 260 | ################################################## 261 | 262 | # ALL SETTINGS 263 | # SECTIONS OF OPTIONS 264 | ALL_SECTIONS="D4D_SETTINGS NGINX_SETTINGS PHP_SETTINGS MYSQL_SETTINGS DEBIAN_SETTINGS NODE_JS_SETTINGS PMA_SETTINGS" 265 | 266 | D4D_SETTINGS="YARN WKHTMLTOPDF" 267 | 268 | NGINX_SETTINGS="NGINX_CACHE" 269 | 270 | PHP_SETTINGS="PHP_VERSION XDEBUG IONCUBE" 271 | 272 | MYSQL_SETTINGS="MYSQL_VERSION" 273 | 274 | DEBIAN_SETTINGS="DEBIAN_VERSION" 275 | 276 | NODE_JS_SETTINGS="NODE_JS_VERSION" 277 | 278 | PMA_SETTINGS="PMA_AUTO_LOGIN" 279 | 280 | showVersion() { 281 | echo "${DOCKER_SCRIPT_VER} (rev: 0001)" 282 | } 283 | 284 | generateHelp() { 285 | for section in ${HELP_SECTIONS}; do 286 | DESC=${section}_DESC 287 | echo " +-----------------------------------------------------------+" 288 | printf " | %-55s %-2s|\n" "$(eval_var ${DESC}):" 289 | 290 | BUILDSET="${section}_SET" 291 | BUILD_ADD_TO_OUT="${section}_REQADD" 292 | for setting in $(eval_var ${BUILDSET}); do 293 | ADDIT="" 294 | for i in $(eval_var ${BUILD_ADD_TO_OUT}); do 295 | ADDIT_VAR=`echo "${i}_ADDIT" | tr "[a-z]" "[A-Z]"` 296 | if [ "$i" = "${setting}" ]; then 297 | ADDIT="$(eval_var ${ADDIT_VAR})" 298 | fi 299 | done 300 | printf " | %-55s %-2s|\n" " $0 ${setting} ${ADDIT}" 301 | done 302 | done 303 | } 304 | 305 | doCheckPackage() { 306 | # $1 package name 307 | 308 | which $1 > /dev/null 2>&1 309 | if [ $? != 0 ]; then 310 | case "$1" in 311 | pwgen) 312 | if [ ${OS} = "FreeBSD" ]; then 313 | pkg install $1 314 | elif [ -e ${DEBIAN_VERSION} ]; then 315 | apt-get install $1 316 | else 317 | if [ ${OS_CENTOS_VERSION} = "7" ]; then 318 | wget http://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/pwgen-2.08-1.el7.x86_64.rpm && rpm -ivh pwgen-2.08-1.el7.x86_64.rpm && rm pwgen-2.08-1.el7.x86_64.rpm 319 | fi 320 | 321 | if [ ${OS_CENTOS_VERSION} = "8" ]; then 322 | wget https://download-ib01.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/p/pwgen-2.08-3.el8.x86_64.rpm && rpm -ivh pwgen-2.08-3.el8.x86_64.rpm && rm pwgen-2.08-3.el8.x86_64.rpm 323 | fi 324 | fi 325 | ;; 326 | docker) 327 | if [ ${OS} = "FreeBSD" ]; then 328 | curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh && sudo usermod -aG docker ${USER} && rm get-docker.sh 329 | elif [ -e ${DEBIAN_VERSION} ]; then 330 | curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh && sudo usermod -aG docker ${USER} && rm get-docker.sh 331 | else 332 | if [ ${OS_CENTOS_VERSION} != "8" ]; then 333 | curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh && sudo usermod -aG docker ${USER} && rm get-docker.sh 334 | else 335 | sudo dnf install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm && curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh && sudo usermod -aG docker ${USER} && rm get-docker.sh 336 | fi 337 | fi 338 | ;; 339 | certutil) 340 | if [ ${OS} = "FreeBSD" ]; then 341 | pkg install libnss3-tools 342 | elif [ -e ${DEBIAN_VERSION} ]; then 343 | apt-get install libnss3-tools 344 | else 345 | yum install libnss3-tools 346 | fi 347 | ;; 348 | mkcert) 349 | export VER="v1.4.1" && wget -O mkcert https://github.com/FiloSottile/mkcert/releases/download/${VER}/mkcert-${VER}-linux-amd64 && chmod +x mkcert && mv mkcert /usr/local/bin 350 | ;; 351 | 352 | * ) 353 | if [ ${OS} = "FreeBSD" ]; then 354 | pkg install $1 355 | elif [ -e ${DEBIAN_VERSION} ]; then 356 | apt-get install $1 357 | else 358 | yum install $1 359 | fi 360 | ;; 361 | esac 362 | fi 363 | } 364 | 365 | doRemovePackage() { 366 | # $1 package name 367 | 368 | which $1 > /dev/null 2>&1 369 | if [ $? == 0 ]; then 370 | case "$1" in 371 | docker) 372 | if [ ${OS} = "FreeBSD" ]; then 373 | pkg remove docker-ce docker-ce-cli 374 | elif [ -e ${DEBIAN_VERSION} ]; then 375 | apt-get remove docker-ce docker-ce-cli 376 | else 377 | yum remove docker-ce docker-ce-cli 378 | fi 379 | ;; 380 | certutil) 381 | if [ ${OS} = "FreeBSD" ]; then 382 | pkg remove libnss3-tools 383 | elif [ -e ${DEBIAN_VERSION} ]; then 384 | apt-get remove libnss3-tools 385 | else 386 | yum remove libnss3-tools 387 | fi 388 | ;; 389 | mkcert) 390 | rm /usr/local/bin/mkcert 391 | ;; 392 | * ) 393 | if [ ${OS} = "FreeBSD" ]; then 394 | pkg remove $1 395 | elif [ -e ${DEBIAN_VERSION} ]; then 396 | apt-get remove $1 397 | else 398 | yum remove $1 399 | fi 400 | ;; 401 | esac 402 | fi 403 | } 404 | 405 | doInstall() { 406 | if [ "$(id -u)" != "0" ]; then 407 | echo "You must be root to execute the script. Exiting." 408 | exit 1 409 | fi 410 | 411 | if [ "${OS_CENTOS_VERSION}" = "6" ]; then 412 | echo "Unsupported distribution. Exiting." 413 | exit 1 414 | fi 415 | 416 | # Install PWGen 417 | doCheckPackage pwgen 418 | 419 | # Install cURL 420 | doCheckPackage curl 421 | 422 | # Install the latest Docker CE version 423 | doCheckPackage docker 424 | 425 | # Install certutil 426 | doCheckPackage certutil 427 | 428 | # Install mkcert 429 | doCheckPackage mkcert 430 | } 431 | 432 | doUninstall() { 433 | if [ "$(id -u)" != "0" ]; then 434 | echo "You must be root to execute the script. Exiting." 435 | exit 1 436 | fi 437 | 438 | if [ "${OS_CENTOS_VERSION}" = "6" ]; then 439 | echo "Unsupported distribution. Exiting." 440 | exit 1 441 | fi 442 | 443 | # Remove PWGen 444 | doRemovePackage pwgen 445 | 446 | # Remove Docker CE 447 | doRemovePackage docker 448 | 449 | # Remove certutil 450 | doRemovePackage certutil 451 | 452 | # Remove mkcert 453 | doRemovePackage mkcert 454 | } 455 | 456 | start() { 457 | ./main start 458 | 459 | # Load .env file into the current shell script 460 | source ${D4D_ENV} 461 | 462 | COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker compose build --parallel 463 | 464 | # Clears the screen. 465 | clear 466 | 467 | # Start server 468 | echo "Starting docker containers..." 469 | docker compose --env-file ${D4D_ENV} up -d --remove-orphans 470 | 471 | if [ "${SUPERVISOR}" = "yes" ]; then 472 | echo "Starting supervisor..." 473 | docker compose exec -u root php service supervisor start && docker compose exec -u root php supervisorctl reread && docker compose exec -u root php supervisorctl update && docker compose exec -u root php supervisorctl start messenger-consume:* 474 | fi 475 | 476 | # Documentation for end user 477 | echo "" 478 | echo "The following information has been set:" 479 | echo "" 480 | echo "Server IP: 127.0.0.1" 481 | echo "Server Hostname: ${PROJECT_DOMAIN_1}" 482 | echo "" 483 | echo "To login now, follow this link:" 484 | echo "" 485 | echo "Project URL: http://${PROJECT_DOMAIN_1}" 486 | echo "phpMyAdmin: http://${PROJECT_DOMAIN_1}:${PORT_PMA}" 487 | 488 | if [ "${MAILHOG}" = "yes" ] || [ "${RABBITMQ}" = "yes" ] || [ "${ELASTICSEARCH}" = "yes" ]; then 489 | echo "" 490 | echo "Extra features:" 491 | fi 492 | 493 | if [ "${MAILHOG}" = "yes" ]; then 494 | echo "MailHog: http://${PROJECT_DOMAIN_1}:${PORT_MAILHOG_HTTP}" 495 | fi 496 | 497 | if [ "${RABBITMQ}" = "yes" ]; then 498 | echo "RabbitMQ: http://${PROJECT_DOMAIN_1}:${PORT_RABBITMQ_MANAGEMENT}" 499 | fi 500 | 501 | if [ "${ELASTICSEARCH}" = "yes" ]; then 502 | echo "Elasticsearch: http://${PROJECT_DOMAIN_1}:${PORT_ELASTICSEARCH_HEAD}" 503 | fi 504 | 505 | echo "" 506 | echo "Thank you for using Docker for Symfony. Should you have any questions, don't hesitate to contact us at support@d4d.lt" 507 | 508 | if [ "${DEFAULT_CONTAINER}" != "" ]; then 509 | dockerComposeExec ${DEFAULT_CONTAINER} 510 | fi 511 | } 512 | 513 | stop() { 514 | docker compose down 515 | } 516 | 517 | restart() { 518 | ./d4d stop && ./d4d start 519 | } 520 | 521 | dockerComposeExec() { 522 | # $1 command 523 | # $2 user 524 | 525 | if [ "${1}" == "php" ] && [ "${2}" != "" ]; then 526 | docker compose exec -u $2 $1 bash 527 | else 528 | docker compose exec $1 bash 529 | fi 530 | } 531 | 532 | logs() { 533 | # $1 command 534 | 535 | CURRENT_DIR=`basename ${WORK_DIR}` 536 | CONTAINER_NAME="${CURRENT_DIR}_${1}_1" 537 | CONTAINER_ID=`docker ps -aqf name=^${CONTAINER_NAME}$` 538 | 539 | docker logs -f ${CONTAINER_ID} 540 | } 541 | 542 | doMysqlDump() { 543 | # Load .env file into the current shell script 544 | source ${D4D_ENV} 545 | 546 | docker compose exec mysql bash /tmp/db/mysql_dump.sh 547 | } 548 | 549 | doDockerBackup() { 550 | if [ "$(id -u)" != "0" ]; then 551 | echo "You must be root to execute the script. Exiting." 552 | exit 1 553 | fi 554 | 555 | if [ "${OS_CENTOS_VERSION}" = "6" ]; then 556 | echo "Unsupported distribution. Exiting." 557 | exit 1 558 | fi 559 | 560 | PROJECT_DIR="`basename ${WORK_DIR}`" 561 | FILE_NAME="${PROJECT_DIR}_$(date +%Y%m%d_%H%M%S).tar.gz" 562 | 563 | tar -zcf "../${FILE_NAME}" --exclude={"${PROJECT_DIR}/project/vendor","${PROJECT_DIR}/project/node_modules","${PROJECT_DIR}/project/var/cache","${PROJECT_DIR}/project/var/log","${PROJECT_DIR}/symfony"} "../${PROJECT_DIR}" 564 | } 565 | 566 | doPrune() { 567 | # Remove all unused containers, networks, images (both dangling and unreferenced), and optionally, volumes. 568 | docker system prune --volumes -a 569 | } 570 | 571 | doPasswd() { 572 | # $1 command 573 | COMMAND=$1 574 | 575 | if [ "${COMMAND}" = "show" ]; then 576 | ./main d4d:passwd:show 577 | fi 578 | } 579 | 580 | blackfire() { 581 | source ${ENV} 582 | 583 | # $1 command 584 | COMMAND=$1 585 | 586 | if [ "${BLACKFIRE}" = "yes" ]; then 587 | if [ "${COMMAND}" = "register" ]; then 588 | echo "Register Blackfire..." 589 | docker compose exec -u root php blackfire agent:config --server-id=${BLACKFIRE_SERVER_ID} --server-token=${BLACKFIRE_SERVER_TOKEN} 590 | docker compose exec -u root php mkdir -p /var/run/blackfire 591 | fi 592 | 593 | if [ "${COMMAND}" = "start" ] || [ "${COMMAND}" == "stop" ] || [ "${COMMAND}" == "restart" ]; then 594 | docker compose exec -u root php blackfire agent:${COMMAND} 595 | fi 596 | fi 597 | } 598 | 599 | mkcert() { 600 | source ${ENV} 601 | 602 | # $1 command 603 | COMMAND=$1 604 | if [ "${NGINX_SSL}" = "yes" ]; then 605 | MKCERT=$(whereis mkcert) | awk '{print $2}' 606 | 607 | if [ "${COMMAND}" = "install" ]; then 608 | echo "Install the local CA in the system trust store." 609 | /opt/homebrew/bin/mkcert -install 610 | 611 | ./d4d mkcert ssl 612 | fi 613 | 614 | if [ "${COMMAND}" = "ssl" ]; then 615 | DOMAINS="${PROJECT_DOMAIN_1} ${PROJECT_DOMAIN_2} ${PROJECT_DOMAIN_3} ${PROJECT_DOMAIN_4}" 616 | MKCERT -cert-file ${WORK_DIR}/user/nginx/ssl/d4d.pem -key-file ${WORK_DIR}/user/nginx/ssl/d4d-key.pem ${DOMAINS} 617 | fi 618 | fi 619 | } 620 | 621 | allSettings() { 622 | for section in $ALL_SECTIONS; do 623 | DESC=${section}_DESC 624 | echo "------------------------------------------" 625 | echo "$(eval_var ${DESC})" 626 | echo "------------------------------------------" 627 | for setting in $(eval_var ${section}); do 628 | SETTING_NAME=`echo $setting | tr "[A-Z]" "[a-z]"` 629 | POSSIBLE_VALUES_VAR=${setting}_SET 630 | POSSIBLE_VALUES="`echo $(eval_var ${POSSIBLE_VALUES_VAR}) | awk -v OFS=", " '$1=$1'`" 631 | DEFAULT_VALUE=${setting}_DEF 632 | CURRENT_VALUE=${setting}_OPT 633 | echo -n "${SETTING_NAME}: ${POSSIBLE_VALUES}. Current value: $(eval_var ${CURRENT_VALUE}). Default value: $(eval_var ${DEFAULT_VALUE})." 634 | if [ "$1" = "full" ]; then 635 | DESCRIPTION="${setting}_DESC" 636 | echo " Description: $(eval_var ${DESCRIPTION})" 637 | else 638 | echo "" 639 | fi 640 | done 641 | echo "" 642 | done 643 | } 644 | 645 | git() { 646 | awk 'NR==1,/.env.secret/' ${D4D_ENV} > ${WORK_DIR}/.env.git 647 | 648 | if [ "$OS" = 'Darwin' ]; then 649 | # for MacOS 650 | sed -i '' '$d' ${WORK_DIR}/.env.git 651 | else 652 | # for Linux and Windows 653 | sed -i'' '$d' ${WORK_DIR}/.env.git 654 | fi 655 | } 656 | 657 | info() { 658 | source ${D4D_ENV} 659 | 660 | IP_NGINX=`getContainerIpAddress nginx` 661 | IP_PHP=`getContainerIpAddress php` 662 | IP_MYSQL=`getContainerIpAddress mysql` 663 | IP_PMA=`getContainerIpAddress phpmyadmin` 664 | 665 | NGINX_INFO=`docker compose exec nginx dpkg -s nginx | grep '^Version: ' | cut -d '-' -f1` 666 | 667 | case "${MYSQL_INST}" in 668 | mysql) 669 | if [ "${MYSQL_VERSION}" != "8.0" ]; then 670 | MYSQL_INFO=`docker compose exec mysql dpkg -s mysql-server | grep '^Version' | cut -d ':' -f2 | cut -d ' ' -f2 | cut -d '-' -f1` 671 | else 672 | MYSQL_INFO=`docker compose exec mysql dpkg -s mysql-common | grep '^Version' | cut -d ':' -f2 | cut -d ' ' -f2 | cut -d '-' -f1` 673 | fi 674 | ;; 675 | mariadb) 676 | MYSQL_INFO=`docker compose exec mysql dpkg -s mariadb-server | grep '^Version' | cut -d ':' -f3 | cut -d '+' -f1` 677 | ;; 678 | * ) 679 | MYSQL_INFO=`docker compose exec mysql dpkg -s mysql-server | grep '^Version' | cut -d ':' -f2 | cut -d ' ' -f2 | cut -d '-' -f1` 680 | ;; 681 | esac 682 | 683 | PHP_INFO=`docker compose exec php php -v | grep '^PHP' | cut -d ' ' -f2 | tr -d "\r\n"` 684 | 685 | mainHeader 686 | printf " | %-55s %-2s|\n" "Docker Information:" 687 | printf " | %-55s %-2s|\n" "`docker --version`" 688 | printf " | %-55s %-2s|\n" "`docker compose --version`" 689 | printf " +%-55s+\n" "-----------------------------------------------------------" 690 | printf " | %-55s %-2s|\n" "D4D Information:" 691 | printf " | %-55s %-2s|\n" "NGINX: ${NGINX_INFO}" 692 | printf " | %-55s %-2s|\n" "PHP: ${PHP_INFO}" 693 | printf " | %-55s %-2s|\n" "MySQL: ${MYSQL_INFO}" 694 | printf " +%-55s+\n" "-----------------------------------------------------------" 695 | printf " | %-55s %-2s|\n" "IP Information:" 696 | printf " | %-55s %-2s|\n" "NGINX: ${IP_NGINX}" 697 | printf " | %-55s %-2s|\n" "PHP: ${IP_PHP}" 698 | printf " | %-55s %-2s|\n" "MySQL: ${IP_MYSQL}" 699 | printf " | %-55s %-2s|\n" "phpMyAdmin: ${IP_PMA}" 700 | printf " +%-55s+\n" "-----------------------------------------------------------" 701 | } 702 | 703 | updateImages() { 704 | source ${D4D_ENV} 705 | 706 | IMAGES=('debian:'${DEBIAN_VERSION} 'php:'${PHP_VERSION}'-fpm') 707 | 708 | if [ "${MYSQL_INST}" = "mysql" ]; then 709 | IMAGES+=('mysql:'${MYSQL_VERSION}) 710 | elif [ "${MYSQL_INST}" = "mariadb" ]; then 711 | IMAGES+=('mariadb:'${MARIADB_VERSION}) 712 | fi 713 | 714 | if [ "${MAILHOG}" = "yes" ]; then 715 | IMAGES+=('mailhog/mailhog') 716 | fi 717 | 718 | if [ "${PMA}" = "yes" ]; then 719 | IMAGES+=('phpmyadmin/phpmyadmin') 720 | fi 721 | 722 | if [ "${REDIS}" = "yes" ]; then 723 | IMAGES+=('redis:latest') 724 | fi 725 | 726 | if [ "${RABBITMQ}" = "yes" ]; then 727 | IMAGES+=('rabbitmq:'${RABBITMQ_VERSION}'-management') 728 | fi 729 | 730 | if [ "${ELASTICSEARCH}" = "yes" ]; then 731 | IMAGES+=('docker.elastic.co/elasticsearch/elasticsearch:'${ELASTICSEARCH_VERSION}) 732 | IMAGES+=('tobias74/elasticsearch-head:6') 733 | fi 734 | 735 | if [ "${NGROK}" = "yes" ]; then 736 | IMAGES+=('wernight/ngrok:latest') 737 | fi 738 | 739 | if [ "${MONGODB}" = "yes" ]; then 740 | IMAGES+=('mongo:'${MONGODB_VERSION}) 741 | fi 742 | 743 | if [ "${BLACKFIRE}" = "yes" ]; then 744 | IMAGES+=('blackfire/blackfire') 745 | fi 746 | 747 | for i in "${IMAGES[@]}" 748 | do 749 | docker pull $i 750 | done 751 | } 752 | 753 | mainHeader() { 754 | printf " +%-55s+\n" "-----------------------------------------------------------" 755 | printf " | %-55s %-2s|\n" "Docker for Symfony (PHP-FPM - NGINX - MySQL)" 756 | printf " | %-55s %-2s|\n" "Written by Vasilij Dusko" 757 | printf " | %-55s %-2s|\n" "Version: $(showVersion)" 758 | printf " +%-55s+\n" "-----------------------------------------------------------" 759 | } 760 | 761 | showHelp() { 762 | mainHeader 763 | generateHelp 764 | printf " +%-55s+\n" "-----------------------------------------------------------" 765 | } 766 | 767 | case "$1" in 768 | install) doInstall; 769 | ;; 770 | uninstall) doUninstall; 771 | ;; 772 | start) start 773 | ;; 774 | stop) stop 775 | ;; 776 | restart) restart 777 | ;; 778 | exec) dockerComposeExec $2 $3 779 | ;; 780 | logs) logs $2 781 | ;; 782 | prune) doPrune 783 | ;; 784 | mysql_dump) doMysqlDump 785 | ;; 786 | docker_backup) doDockerBackup 787 | ;; 788 | passwd) doPasswd $2 789 | ;; 790 | blackfire) blackfire $2 791 | ;; 792 | mkcert) mkcert $2 793 | ;; 794 | opt_help) allSettings $2 795 | ;; 796 | git) git 797 | ;; 798 | info) info 799 | ;; 800 | update_images) updateImages 801 | ;; 802 | self-update) ./main self-update 803 | ;; 804 | * ) showHelp 805 | exit 0 806 | ;; 807 | esac 808 | --------------------------------------------------------------------------------