├── .env ├── .gitignore ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── caddy ├── Dockerfile ├── config │ └── Caddyfile └── start.sh ├── data └── .gitkeep ├── docker-compose.yml └── nginx ├── Dockerfile ├── nginx.conf └── nginx.vh.default.conf /.env: -------------------------------------------------------------------------------- 1 | # your local IP, for remote debug in XDebug 2 | DEBUG_HOST=192.168.0.11 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | data -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "XDebug", 6 | "type": "php", 7 | "request": "launch", 8 | "port": 9000, 9 | // Path to your source in container 10 | "serverSourceRoot": "/var/www/html", 11 | // Path to your local source 12 | "localSourceRoot": "${workspaceRoot}/src" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Juliano Petronetto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Containerized PHP application for Laravel Development 2 | 3 | ## What is this? 4 | 5 | This an example to how using Docker as development environment for Laravel/Lumen. 6 | 7 | ## What is included 8 | 9 | This docker-compose contains the basic pieces to build an applications with PHP. 10 | - PHP7 11 | - Nginx or Caddy 12 | - Postgres 13 | - Redis 14 | 15 | ## How to use 16 | 17 | ### 1. Get the files and spin up containers 18 | 19 | ```bash 20 | # Get shipping-docker files 21 | git clone https://github.com/petronetto/laravel-docker.git 22 | cd laravel-docker 23 | 24 | # Start the app, run containers in the background 25 | # This will download and build the images the first time you run this 26 | docker-compose up -d 27 | ``` 28 | 29 | At this point, we've created containers and have them up and running. However, we didn't create a Laravel application to serve yet. We waited because we wanted a PHP image to get created so we can re-use it and run `composer` commands. 30 | 31 | ### 2. Create a new Laravel application 32 | 33 | > **Note:** You need delete the files in path `app` before run the command bellow. 34 | 35 | From directory `laravel-docker` the following command to create the Laravel app: 36 | ```bash 37 | docker run -it --rm \ 38 | -v $(pwd)/app:/app \ 39 | -w /app \ 40 | petronetto/php7-alpine \ 41 | composer create-project laravel/laravel . 42 | ``` 43 | 44 | Now, install Redis driver: 45 | ```sh 46 | docker run -it --rm \ 47 | -v $(pwd)/app:/app \ 48 | -w /app \ 49 | petronetto/php7-alpine \ 50 | composer require predis/predis 51 | ``` 52 | 53 | > In Linux, maybe you need run the follow ommand to set directory ownership to you `sudo chown -R $USER:$USER .` 54 | 55 | Edit the `app/.env` file to have correct settings for our containers. Adjust the following as necessary: 56 | 57 | ``` 58 | DB_CONNECTION=pgsql 59 | DB_HOST=database 60 | DB_PORT=5432 61 | DB_DATABASE=homestead 62 | DB_USERNAME=homestead 63 | DB_PASSWORD=secret 64 | 65 | BROADCAST_DRIVER=log 66 | CACHE_DRIVER=redis 67 | SESSION_DRIVER=redis 68 | SESSION_LIFETIME=120 69 | QUEUE_DRIVER=redis 70 | 71 | REDIS_HOST=redis 72 | REDIS_PASSWORD=null 73 | REDIS_PORT=6379 74 | ``` 75 | 76 | > If you already have an application, you can move it to the `app` directory here. Else, you can adjust the shared volume file paths within the `docker-compose.yml` file. 77 | > 78 | > If you edit the `docker-compose.yml` file, run `docker-compose down; docker-compose up -d` to suck in the new Volume settings. 79 | 80 | **NOTE**: If you're not running Docker Mac/Windows (which run Docker in a small virtualized layer), you may need to set permissions on the shared directories that Laravel needs to write to. The following will let Laravel write the storage and bootstrap directories: 81 | 82 | ```bash 83 | # From directory laravel-docker 84 | sudo chmod -R o+rw app/bootstrap app/storage 85 | ``` 86 | 87 | ### 3. (Optionally) Add Auth Scaffolding: 88 | 89 | If you'd like, we can add Laravel's Auth scaffolding as well. To do that, we need to run some Artisan commands: 90 | 91 | ```bash 92 | # Scaffold authentication views/routes 93 | docker exec -it php-fpm php artisan make:auth 94 | 95 | # Run migrations for auth scaffolding 96 | docker exec -it php-fpm php artisan migrate 97 | ``` 98 | 99 | ## Remote debug 100 | 101 | The container is configured to run the file that bootstrap applications in folder `/app/public`, because I use Laravel/Lumen by default, so, if you don't use a framework that bootstrap the application in this folder, you must put your source files there. 102 | To the debug works, you must: 103 | 104 | 1) Set your local IP address in `XDEBUG_HOST` environment variable in `docker-compose.yml`. 105 | 106 | 2) Configure your editor/IDE to map the local source and the remote source. 107 | 108 | ### VS Code 109 | Install [PHP Debug Extension](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug). 110 | 111 | Put this config in your `launch.json`: 112 | 113 | >**NOTE** this example will map the local folder `app`, to `/app` on the container. Remenber that container is configured to boostrap in `/app/public`, as the example provided in this repo. 114 | 115 | ```json 116 | //launch.json 117 | { 118 | "version": "0.2.0", 119 | "configurations": [ 120 | { 121 | "name": "XDebug", 122 | "type": "php", 123 | "request": "launch", 124 | "port": 9000, 125 | "pathMappings": { 126 | "/app": "${workspaceRoot}" 127 | }, 128 | "ignore": ["**/vendor/**/*.php"] 129 | } 130 | ] 131 | } 132 | ``` 133 | 134 | Check the Sublime and PHPStorm configs [here](https://github.com/petronetto/php7-alpine#remote-debug) 135 | 136 | 137 | Enjoy! 138 | -------------------------------------------------------------------------------- /caddy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.7 2 | 3 | LABEL maintainer="Juliano Petronetto " 4 | 5 | ENV PHP_SERVER=php-fpm 6 | 7 | ARG plugins=http.upload 8 | 9 | RUN apk add --update openssh-client tar curl 10 | 11 | RUN curl --silent --show-error --fail --location --header \ 12 | "Accept: application/tar+gzip, application/x-gzip, application/octet-stream" -o - \ 13 | "https://caddyserver.com/download/linux/amd64?plugins=${plugins}&license=personal" \ 14 | | tar --no-same-owner -C /usr/bin/ -xz caddy && \ 15 | chmod 0755 /usr/bin/caddy && \ 16 | addgroup -S caddy && \ 17 | adduser -D -S -H -s /sbin/nologin -G caddy caddy && \ 18 | /usr/bin/caddy -version 19 | 20 | VOLUME /app 21 | 22 | WORKDIR /app 23 | 24 | ADD config/Caddyfile /etc/Caddyfile 25 | 26 | RUN chown -R caddy:caddy /app 27 | 28 | USER caddy 29 | 30 | ENTRYPOINT ["/usr/bin/caddy"] 31 | 32 | CMD ["--conf", "/etc/Caddyfile"] -------------------------------------------------------------------------------- /caddy/config/Caddyfile: -------------------------------------------------------------------------------- 1 | *:8080 { 2 | root /app/public 3 | tls off 4 | gzip 5 | log stdout 6 | errors stderr 7 | fastcgi / {%PHP_SERVER%}:9000 php 8 | rewrite { 9 | to {path} {path}/ /index.php?{query} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /caddy/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | /usr/bin/caddy -conf="/etc/Caddyfile" -------------------------------------------------------------------------------- /data/.gitkeep: -------------------------------------------------------------------------------- 1 | !.gitignore -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # I use ENV variables to name my containers and set the ports 2 | # to change, replate it here or in .env file 3 | version: '3' 4 | services: 5 | #--------------------------------------------- 6 | # NGINX Container 7 | #--------------------------------------------- 8 | php-fpm: 9 | container_name: php-fpm 10 | image: petronetto/php7-alpine 11 | restart: always 12 | environment: 13 | XDEBUG_ENABLE: 1 14 | XDEBUG_HOST: ${DEBUG_HOST} 15 | XDEBUG_REMOTE_PORT: 9000 16 | NEWRELIC_ENABLED: 0 17 | NEWRELIC_LICENSE: "" 18 | volumes: 19 | - ./app:/app 20 | links: 21 | - database 22 | - redis 23 | #--------------------------------------------- 24 | # Web Server Container 25 | #--------------------------------------------- 26 | webserver: 27 | container_name: webserver 28 | # build: ./nginx 29 | build: ./caddy 30 | links: 31 | - php-fpm 32 | volumes: 33 | - ./app:/app 34 | ports: 35 | - 8080:8080 36 | #--------------------------------------------- 37 | # Database Container 38 | #--------------------------------------------- 39 | database: 40 | container_name: database 41 | restart: always 42 | image: postgres:alpine 43 | ports: 44 | - 5432:5432 45 | environment: 46 | POSTGRES_DB: homestead 47 | POSTGRES_USER: homestead 48 | POSTGRES_PASSWORD: secret 49 | volumes: 50 | - ./database:/var/lib/postgresql 51 | #--------------------------------------------- 52 | # Caddy Container 53 | #--------------------------------------------- 54 | redis: 55 | container_name: redis 56 | image: redis:alpine 57 | restart: always 58 | -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.12-alpine 2 | 3 | LABEL maintainer="Juliano Petronetto " 4 | 5 | # Install packages 6 | RUN apk --update add --no-cache tzdata \ 7 | && rm -rf /var/cache/apk/* \ 8 | && cp /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime \ 9 | && echo "America/Sao_Paulo" > /etc/timezone \ 10 | && apk del tzdata && rm -rf /var/cache/apk/* \ 11 | && mkdir /app \ 12 | && chown -R nginx:nginx /app \ 13 | && chown -R nginx:nginx /var/cache/nginx /etc/nginx \ 14 | && chmod -R g=u /var/cache/nginx /etc/nginx 15 | 16 | COPY nginx.conf /etc/nginx/nginx.conf 17 | COPY nginx.vh.default.conf /etc/nginx/conf.d/default.conf 18 | 19 | USER nginx -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 5; 2 | 3 | error_log /dev/stderr warn; 4 | 5 | pid /tmp/nginx.pid; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | include /etc/nginx/mime.types; 13 | default_type application/octet-stream; 14 | 15 | client_max_body_size 5m; 16 | 17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 18 | '$status $body_bytes_sent "$http_referer" ' 19 | '"$http_user_agent" "$http_x_forwarded_for"'; 20 | 21 | access_log /dev/stdout main; 22 | 23 | sendfile on; 24 | 25 | keepalive_timeout 2; 26 | 27 | gzip on; 28 | gzip_disable "msie6"; 29 | gzip_vary on; 30 | gzip_proxied any; 31 | gzip_comp_level 6; 32 | gzip_buffers 16 8k; 33 | gzip_http_version 1.1; 34 | gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 35 | 36 | 37 | index index.php index.html; 38 | 39 | include /etc/nginx/conf.d/*.conf; 40 | } -------------------------------------------------------------------------------- /nginx/nginx.vh.default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8080; 3 | listen [::]:8080 default ipv6only=on; 4 | 5 | root /app/public; 6 | index index.php index.html index.htm; 7 | 8 | gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 9 | 10 | sendfile off; 11 | 12 | location ~ \.php$ { 13 | try_files $uri /index.php =404; 14 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 15 | fastcgi_pass php-fpm:9000; 16 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 17 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 18 | fastcgi_index index.php; 19 | include fastcgi_params; 20 | } 21 | 22 | location ~ ^(.*)$ { 23 | try_files $uri $uri/ /index.php?p=$uri&$args; 24 | } 25 | 26 | location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|ttf|ttc|otf|eot|woff)$ { 27 | try_files $uri /index.php?$query_string; 28 | expires max; 29 | add_header Pragma public; 30 | add_header Cache-Control "public, must-revalidate, proxy-revalidate"; 31 | } 32 | 33 | location ~* \.(?:css|js)$ { 34 | try_files $uri /index.php?$query_string; 35 | expires 1y; 36 | add_header Cache-Control "public"; 37 | } 38 | 39 | # deny access to . files, for security 40 | location ~* (?:^|/)\. { 41 | access_log /dev/stdout; 42 | log_not_found on; 43 | deny all; 44 | } 45 | 46 | location ~* (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ { 47 | deny all; 48 | access_log /dev/stdout; 49 | log_not_found on; 50 | } 51 | 52 | } --------------------------------------------------------------------------------