Setup your own project with WebDev
Short explaination
Instead of using on the examples from the example repository, we will setup a project with WebDev from the ground up.
Creating the folder structure
Since the development environment is based on devcontainer, we need to create first a folder called .devcontainer
in your project root. Afterwards create the following files and folders as shown below. The files can be empty for now and we will go through all of them in the next section.
.
└─ .devcontainer
├─ scripts
│ └─ .gitkeep
├─ tools
│ ├─ adminer.php
│ ├─ phpinfo.php
│ └─ xdebuginfo.php
├─ traefik
│ ├─ certs
│ │ └─ .gitkeep
│ └─ config
│ │ └─ traefik.yml
├─ vhost
│ └─ .gitkeep
├─ .gitignore
├─ devcontainer.json
├─ docker-compose.yml
└─ webdev.ynl
Scripts folder (line 3)
As in detail explained in Extending WebDev, we can add custom commands to WebDev. This folder is the default folder in which custom scripts will be searched for. Further down in this tutorial, we will create a script that setups our system.
Tools folder (line 5)
Currently there are three scripts included. First one is adminer.php
which is an alternative to phpmyadmin and consists of one file. The content of that file can be downloaded here.
Content for phpinfo.php
<?php
phpinfo();
Content for xdebuginfo.php
<?php
xdebug_info();
Traefik folder (line 9)
Traefik is used as reverse proxy and helps managing SSL Certificates for our dev domain and the routing of the subdomains to their correct service.
The certs
directory only needs a .gitkeep
file as traefik will generate the certificates on the first start of the development environment.
For traefik to work, we need to add a little config file(line 13), which content is the following:
global:
sendAnonymousUsage: false
api:
dashboard: true
insecure: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
watch: true
exposedByDefault: false
file:
filename: /etc/traefik/dynamic.yml
watch: true
log:
level: DEBUG
format: common
entryPoints:
http:
address: ":80"
http:
redirections:
entryPoint:
to: https
scheme: https
https:
address: ":443"
vhost (Line 14)
The vhost
folder will contain the virtual hosts configurations files for apache. These will be generated by WebDev on startup.
.gitignore (Line 16)
This file contains dynamic files that are generated by WebDev and should not be added to the git repository.
.createDoneLock
vhost/*.conf
traefik/certs/*.pem
docker-compose.proxy.yml
traefik/config/dynamic.yml
devcontainer.json (Line 17)
This is an example on how the devcontainer.json
could look like. You can use it as a starting point to customize your environment with the extension you need for your IDE etc. You can find a detailed explaination about this file here.
To get started, you should change the value for name (line 4) to match your project name.
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/php
{
"name": "WebDev Development Environment",
"dockerComposeFile": ["docker-compose.yml", "docker-compose.proxy.yml"],
"service": "devcontainer",
"runServices": ["devcontainer"],
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
"settings": {},
"extensions": [
"in4margaret.compareit",
"DEVSENSE.composer-php-vscode",
"donjayamanne.githistory",
"eamodio.gitlens",
"DEVSENSE.intelli-php-vscode",
"DEVSENSE.phptools-vscode",
"marabesi.php-import-checker",
"DEVSENSE.profiler-php-vscode",
"bmewburn.vscode-intelephense-client",
"xdebug.php-debug",
"Vue.volar",
"dbaeumer.vscode-eslint",
"phil294.git-log--graph",
"zackiles.cursor-workbench"
]
}
},
"forwardPorts": [8080,3306,8025,8081,8082],
"portsAttributes": {
"8080": {
"label": "Apache Webserver",
"onAutoForward": "notify"
},
"3306": {
"label": "MySQL Database",
"onAutoForward": "notify"
},
"8025": {
"label": "Mailpit Webinterface",
"onAutoForward": "notify"
},
"8081": {
"label": "PHPMyAdmin",
"onAutoForward": "notify"
},
"8082": {
"label": "PHPCacheAdmin",
"onAutoForward": "notify"
}
},
"initializeCommand": "webdev workspaces-on-init --no-header && webdev tasks init --no-header",
"postStartCommand": "sudo webdev workspaces-post-start --no-header && webdev tasks start --no-header",
"postCreateCommand": "sudo ln -sf ~/webdev/webdev.sh /usr/local/bin/webdev && webdev tasks create --no-header",
"remoteUser": "webdev",
"workspaceFolder": "/var/www/html/",
"containerEnv": {
"WEBDEV_WORKSPACE_FOLDER": "/var/www/html/",
// We need to set this variable so webdev can determine if it is running within a container or locally
"DEVCONTAINER": "1",
"COMPOSE_PROJECT_NAME": "${localWorkspaceFolderBasename}"
}
}
docker-compose.yml (Line 18)
The docker-compose.yml
defines all services that should be available in our development environment, including the devcontainer
which runs apache, php, node etc. Of course you can add any additional service you may need for your project but it should be a good starting point.
In line 8 you can see that we use ghcr.io/derroylo/devcontainer-prebuilds/shopware:latest
as a base image for our main image. You can of course build your own base image, extend the existing one or choose one of the prebuild Images.
# Docker compose for the development environment
services:
# Base image for our devcontainer
devcontainer:
labels:
com.webdev.category: "devcontainer"
com.webdev.proxy.port: "8080"
image: ghcr.io/derroylo/devcontainer-prebuilds/shopware:latest
container_name: ${COMPOSE_PROJECT_NAME:-devcontainer}-app
volumes:
- ..:/var/www/html:cached
- bashhistory:/commandhistory
- ~/webdev:/home/webdev/webdev
command: sleep infinity
networks:
- webdev-network
ports:
- "8080:8080"
traefik:
image: traefik:latest
container_name: ${COMPOSE_PROJECT_NAME:-devcontainer}-traefik
ports:
- "80:80"
- "443:443"
- "8083:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./traefik/config/traefik.yml:/etc/traefik/traefik.yml:ro"
- "./traefik/config/dynamic.yml:/etc/traefik/dynamic.yml:ro"
- "./traefik/certs/:/etc/certs:ro"
labels:
com.webdev.category: "proxy"
com.webdev.name: "Traefik"
com.webdev.description: "Reverse Proxy for Web Development"
com.webdev.proxy.subdomain: "traefik"
com.webdev.proxy.port: "8080"
networks:
- webdev-network
# MySql Server
# For more infos check: https://hub.docker.com/_/mysql/
mysql:
labels:
com.webdev.category: "database"
com.webdev.name: "MySQL Server"
com.webdev.description: "Relational Database"
image: mysql:8.0
container_name: ${COMPOSE_PROJECT_NAME:-devcontainer}-mysql
networks:
- webdev-network
ports:
# make this port public so it can also accessed via HeidiSQL or similar tools
- 3306:3306
environment:
# mysql root password
- MYSQL_ROOT_PASSWORD=webdev
# create this database by default
- MYSQL_DATABASE=webdev
# allow connections from any host
- MYSQL_ROOT_HOST=%
# Mailpit (can fetch all outgoing mails and show them via webinterface)
# For more infos check: https://hub.docker.com/r/axllent/mailpit
mailpit:
labels:
com.webdev.category: "mail"
com.webdev.name: "Mailpit"
com.webdev.description: "email testing tool"
com.webdev.proxy.subdomain: "mail"
com.webdev.proxy.port: "8025"
image: axllent/mailpit:latest
container_name: ${COMPOSE_PROJECT_NAME:-devcontainer}-mailpit
networks:
- webdev-network
ports:
# make this port public for the webinterface
- 8025:8025
# port for incoming mails
- 1025:1025
# Redis Server
# For more infos check: https://hub.docker.com/_/redis
redis:
labels:
com.webdev.category: "cache"
com.webdev.name: "Redis Server"
com.webdev.description: "In-Memory Key-Value Store"
image: redis:latest
networks:
- webdev-network
container_name: ${COMPOSE_PROJECT_NAME:-devcontainer}-redis
ports:
- 6379:6379
# PhpMyAdmin
# For more infos check: https://hub.docker.com/_/phpmyadmin
phpmyadmin:
labels:
com.webdev.category: "tools"
com.webdev.name: "PhpMyAdmin"
com.webdev.description: "MySQL Admin Tool"
com.webdev.proxy.subdomain: "pma"
com.webdev.proxy.port: "80"
image: phpmyadmin:latest
container_name: ${COMPOSE_PROJECT_NAME:-devcontainer}-pma
depends_on:
- mysql
networks:
- webdev-network
environment:
- PMA_HOST=mysql
- PMA_USER=root
- PMA_PASSWORD=webdev
- UPLOAD_LIMIT=2048M
- PMA_PMADB=pma
ports:
- "8081:80"
volumes:
- /tmp/apache2/logs:/var/log/apache2
# PhpCacheAdmin
# For more infos check: https://hub.docker.com/r/robinn/phpcacheadmin
phpcacheadmin:
labels:
com.webdev.category: "tools"
com.webdev.name: "PhpCacheAdmin"
com.webdev.description: "UI for managing PHP cache systems"
com.webdev.proxy.subdomain: "pca"
com.webdev.proxy.port: "80"
image: robinn/phpcacheadmin
container_name: ${COMPOSE_PROJECT_NAME:-devcontainer}-phpcacheadmin
networks:
- webdev-network
ports:
- "8082:80"
environment:
- PCA_REDIS_0_HOST=redis
- PCA_REDIS_0_PORT=6379
volumes:
- /tmp/apache2/logs:/var/log/apache2
volumes:
bashhistory:
networks:
webdev-network:
driver: bridge
webdev.yml (Line 19)
Last but not least, we need to give WebDev a little config file so it knows what todo on startup etc.
In short we tell WebDev that it should start traefik
and mysql
and define a few tasks that should install our project and show a summary after it started.
For a full example of this file, take a look at the reference section.
services:
active:
- traefik
- mysql
tasks:
fixOwner:
name: Fixes the owner of different folders
create:
- sudo chown -R $(id -u):$(id -g) /home/webdev
services:
name: Start the active services
init:
- webdev services start -d
install:
name: Run composer install and setup everything
onlyMain: false
create:
- webdev project install
apache:
name: Start apache
start:
- apachectl start
info:
name: Show information about the development environment
start:
- WEBDEV_DISABLE_HEADER=1 webdev project-start-summary
Install your project
Before we can start our project, we should create a file that setups the project. We usually don´t want to execute all setup commands manually each time we create a new instance, or when a coworker also wants to work on it. That way we make it easier for everyone to work on this project, without remembering all tasks that needs to be done, so he just needs the project and can directly start working on it.
Create a new folder called tasks
within the scripts
folder. Now create a new file called setup.sh
within that folder, with the following content:
#!/bin/bash
# webDevCommand: install
# webDevBranch: project
# webDevBranchDescription: Commands for the project
# webDevDescription: Install project
Now it heavily depends on your project on what you need to put in here.
An example could look like this:
#!/bin/bash
# webDevCommand: install
# webDevBranch: project
# webDevBranchDescription: Commands for the project
# webDevDescription: Install project
# Install dependencies
composer install
# Write database connection
echo "DATABASE_URL=mysql://root:webdev@mysql:3306/webdev" >> .env.local
So with this commands we would install all composer packages and write the database dsn to our .env.local file. You could also leave this file empty for now and start the dev environment, execute the commands manually and add them to the file afterwards.
Document root
Before we can finally start our project, we need to make sure that the document root folder exists, otherwise the apache webserver will fail to start. When you use one of the prebuild images, then the document root would be public
. To change that folder, you need to edit your webdev.yml
.
...
workspaces:
main:
docRoot: src/public
Adjust the value for docRoot
to your needs.
Starting your project
When you are using VS Code
or one of its forks, like Cursor
, Kiro
or Windsurf
, you just need to open your project in it. Usually you will get a notification that a DevContainer setup was found and asks you if you want to start it. If you click yes, then it will take a few minutes to get everything ready for you. The first time could take a bit longer, since he needs to download all docker images etc.
If you are using PHPStorm
i would not recommend using the integrated DevContainer extension. It works the same way as VS Code
but it will need to install the server side of the IDE into your devcontainer, which would add another 2GB to it. I would recommend to start the devcontainer
environment manually with the command webdev project start
and open the project folder on your host system. If you want to execute commands in your devcontainer
then you can use the command webdev terminal
in your shell.
What todo afterwards?
Well now that everything is running, you can start coding or further adjust it to your needs. Checkout the CLI or Reference docs on how to change the php version for example.