Free tools Windows power users keep installed
One-click scans. No signup required.
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
The quickest reproducible Drupal setup is a two-service Docker Compose project: a Drupal 10 Apache container and a PostgreSQL 16 container. Create a compose.yaml, start it with docker compose up, open http://localhost:8080, and enter postgres as Drupal’s database host. That hostname is the Compose service name; localhost would point back to the Drupal container and fail.
The short example below is suitable for local development. The guide then adds named volumes for Drupal files and PostgreSQL data, explains the installer fields, compares SQLite, MySQL, and PostgreSQL, and covers the failures most often encountered during first startup.
What you need before installing
Docker and Compose
Install Docker Desktop on Windows or macOS, or install Docker Engine, the Docker CLI, and the Docker Compose plugin on Linux. Confirm that both commands work before creating the project:
docker --version
docker compose version
Docker Desktop is convenient for development because it bundles the engine and Compose. Linux is the usual choice for hosting; Drupal documentation describes Windows as supported for development environments. You do not need PHP or PostgreSQL installed directly on the host when both run in containers.
#1 Best Overall
Hardware and Drupal requirements
- Drupal’s 2025 requirements guidance lists about 100 MB for core files. A real site needs additional space for modules, themes, uploaded media, backups, logs, and generated files.
- The same guidance lists PHP 8.3 or a higher PHP 8 version and a minimum PHP memory size of 64 MB. In a container deployment, the Drupal image supplies PHP, but every module still has to be compatible with the PHP version and extensions in that image.
- Keep enough memory for both containers and for PostgreSQL’s working data. A small local site may start with modest resources, while imports, image processing, search, and large caches require more.
Create the Compose project
Make a directory
Create a new directory and change into it. Keeping the Compose file and any environment file together makes later upgrades and backups easier.
mkdir drupal-compose
cd drupal-compose
Write compose.yaml
Save the following as compose.yaml. It follows the Drupal Docker Official Image example and adds explicit named volumes, including a PostgreSQL data volume that the short example omits.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →services:
drupal:
image: drupal:10-apache
ports:
- '8080:80'
volumes:
- drupal_modules:/var/www/html/modules
- drupal_profiles:/var/www/html/profiles
- drupal_themes:/var/www/html/themes
- drupal_sites:/var/www/html/sites
restart: always
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: example
volumes:
- postgres_data:/var/lib/postgresql/data
restart: always
volumes:
drupal_modules:
drupal_profiles:
drupal_themes:
drupal_sites:
postgres_data:
The Drupal service publishes container port 80 as port 8080 on your computer. The four Drupal mounts let the image initialize those directories while keeping modules, installation profiles, themes, and the sites tree when the container is recreated. The PostgreSQL mount stores the database cluster outside the writable container layer.
example is intentionally easy to recognize, not a production password. Replace it before exposing the stack beyond your own machine. If you change the value, use the same value in Drupal’s installer. For a shared project, place the password in an environment file and protect that file rather than committing a real secret to source control.
Start the containers
Run Compose
From the directory containing compose.yaml, run:
docker compose up
Compose pulls the Drupal and PostgreSQL images if they are not already present, creates a private network, creates the named volumes, and starts both services. The command stays attached so you can see initialization messages. When you prefer the terminal back, stop with Ctrl+C and restart in the background with docker compose up -d.
Wait for initialization to finish, then open http://localhost:8080. The Docker image documentation describes the same sequence: run docker compose up, wait for initialization to complete, and visit the published port. If port 8080 is already occupied, change the left side of the mapping, for example '8081:80', and browse to http://localhost:8081.
Rank #2
Check service status and logs
In a second terminal, inspect the project:
docker compose ps
docker compose logs -f drupal
docker compose logs -f postgres
docker compose ps should show both services running. Log output is useful during the first database initialization; PostgreSQL can take longer than Apache to become ready. A Drupal page that appears before PostgreSQL is ready may show a connection error. Wait, refresh the browser, and check the PostgreSQL log before changing credentials.
Complete Drupal’s browser installer
Choose the installation profile
At http://localhost:8080, select the profile appropriate for your site, normally the standard profile for a general installation. Continue until Drupal displays the database configuration form.
Enter PostgreSQL settings
Select PostgreSQL and enter these values for the Compose file above:
| Drupal field | Value | Why |
|---|---|---|
| Database name | postgres |
The default database supplied by the PostgreSQL image when no alternate database name is configured. |
| Database username | postgres |
The default PostgreSQL superuser created by the image. |
| Database password | example |
Matches POSTGRES_PASSWORD in compose.yaml; use your replacement value if you changed it. |
| Database host | postgres |
The Compose service name and an address resolvable by the Drupal container on the internal network. |
| Database port | 5432, or the prefilled default |
PostgreSQL’s container port. It is not the host’s published web port. |
Do not enter localhost for the database host. Inside the Drupal container, localhost means that same Drupal container, where PostgreSQL is not running. Compose’s internal DNS resolves the service name postgres to the database container.
If you later rename the service, change the host in Drupal’s settings to the new service name. If you define POSTGRES_DB, a different PostgreSQL user, or a different password, enter those exact values instead of the defaults shown above.
Finish the site setup
Continue through the form and provide the site name, an administrator account, an administrator password, an administrator email address, and the requested regional settings. Drupal’s Composer documentation describes these database credentials, administrator fields, and basic site information as part of the web setup. Use a strong, unique administrator password even on a development machine if the machine is shared.
Rank #3
When installation completes, sign in and confirm that the front page loads. Check that the administration pages can write configuration and that the sites directory contains the installed site data. Those checks validate that the mounted Drupal volume is writable.
How persistence works
Drupal files
The named volumes in the example hold the directories most commonly changed after installation:
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →drupal_modulesstores contributed or custom modules placed undermodules.drupal_profilesstores installation profiles.drupal_themesstores themes.drupal_sitesstores site-specific settings, uploaded files, and other per-site data undersites.
Container recreation does not erase these volumes. A new Drupal container mounts the same data and can continue serving the installed site. The image’s original example uses volume mounts at these paths for the same initialization and retention behavior; naming them explicitly makes the data easier to identify and manage.
PostgreSQL data
postgres_data is mounted at PostgreSQL’s data directory. Without that mount, deleting and recreating the PostgreSQL container can remove the database stored in its writable layer. The short official example does not show a PostgreSQL volume, so add one before treating that example as durable.
Do not remove the volumes casually. docker compose down stops and removes the containers but normally leaves named volumes. docker compose down -v also removes the named volumes and therefore deletes the Drupal files and PostgreSQL database in this project. Use the latter only when you intentionally want a clean, irreversible local reset.
Backups are separate from volumes
A volume is persistence, not a backup. Protect the PostgreSQL database with regular PostgreSQL dump or snapshot procedures, and copy the Drupal sites data and any custom modules or themes. Test restoration on a separate project. A failed disk, mistaken volume deletion, or corrupted database can affect both containers even though the volumes are correctly configured.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsRank #4
Choose a database for your use case
Drupal supports MariaDB, MySQL, PostgreSQL, and SQLite. The right choice depends on whether the project is disposable, how closely development should resemble production, and what database your hosting environment already provides.
| Database | Containers | Operational complexity | Existing-hosting compatibility | Backup approach | Development-to-production similarity |
|---|---|---|---|---|---|
| SQLite | One Drupal container; no database service | Lowest for a quick local demo | Depends on whether production supports SQLite | Back up the SQLite database file and Drupal files together | Best when production also uses SQLite; otherwise limited |
| PostgreSQL | Drupal plus a PostgreSQL service | Requires a database container, credentials, volume, and database backups | Strong when the target host uses PostgreSQL | Use PostgreSQL’s dump and restore tooling plus file backups | Good match for a multi-service PostgreSQL deployment |
| MySQL | Drupal plus a MySQL service | Similar two-service management and persistence concerns | Strong when the target host uses MySQL or MariaDB | Use the selected server’s dump and restore tooling plus file backups | Good match when production is MySQL-compatible |
SQLite is convenient for a disposable experiment because it avoids a second container. PostgreSQL or MySQL is usually the more representative choice for a site that will move to a multi-service deployment. Switching databases later is a migration project, not a simple change of one installer field, so choose based on the intended destination.
Use SQLite instead of PostgreSQL
The Drupal image supports SQLite without a second database container. Remove the PostgreSQL service and its volume, start only Drupal, and select SQLite in the installer. Drupal will ask for a database file location rather than a network host and password. Keep the Drupal sites volume because it must retain the SQLite file and uploaded files.
SQLite is a sensible choice for a throwaway demonstration or a very small local test. It is less suitable when you need to reproduce production behavior that depends on a separate database server, database-specific extensions, or operational tooling.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Use MySQL or MariaDB
MySQL and MariaDB also require a separate database service. Add the matching official database image, configure its initialization variables, mount its data directory, and use the Compose service name as Drupal’s database host. The database type selected in Drupal must match the server you actually started, and the database name, username, password, and host must match the environment and service names in Compose.
Do not copy PostgreSQL-specific values blindly. PostgreSQL’s default user and port are not universal MySQL or MariaDB settings. Decide the database engine first, then use that engine’s image documentation for its supported environment variables and data path.
Best Value
Install modules that need extra PHP extensions
The Drupal image does not contain every PHP extension that every contributed module may require. If Drupal reports a missing extension, first identify the module’s stated requirement and verify that the extension is absent from the image. Do not edit a running container as a permanent fix; those changes disappear when the container is replaced.
Build a custom image with a Dockerfile that starts with the Drupal image, installs the required extension using the image’s supported build procedure, and then changes the Compose service from image: drupal:10-apache to a local build: configuration. Rebuild and recreate the service after changing the Dockerfile. Keep the Dockerfile under version control so another developer or deployment system can reproduce the same PHP environment.
Recommended Free Tools
Upgrade and operate the project
Inspect before changing anything
docker compose ps
docker compose images
docker compose logs --tail=100 drupal
docker compose logs --tail=100 postgres
Confirm which image tags are running and whether the site is healthy before an upgrade. Keep a database backup and a copy of Drupal files before changing major Drupal or database versions.
Pull newer image builds
docker compose pull
docker compose up -d
Pulling obtains newer images allowed by the tags, and up -d recreates services when their image changes while reusing the named volumes. Image updates do not automatically perform every Drupal application update; follow Drupal’s upgrade procedure for the specific core and module versions you use.
Stop without deleting data
docker compose down
This removes the project’s containers and network while retaining the named volumes. Start it again with docker compose up -d. The Drupal installer should not appear again because the site files and database remain.
Troubleshooting common failures
The browser cannot connect
- Run
docker compose psand confirm the Drupal service is running. - Check that you opened the host port shown in the
portsmapping, normallyhttp://localhost:8080. - If another application owns port 8080, change the host side to an unused port such as
8081:80and use the corresponding URL. - Read
docker compose logs drupalfor an image pull, Apache startup, permission, or PHP error.
Drupal cannot connect to PostgreSQL
- Set the database host to
postgres, notlocalhostor the host computer’s IP address. - Verify that the password in the installer exactly matches
POSTGRES_PASSWORD. - Check that the PostgreSQL container is running and has finished initialization with
docker compose logs postgres. - If you changed database environment variables after the first startup, remember that PostgreSQL initialization variables generally apply only when its data directory is first created. For a disposable project, stop the stack, remove the named volume deliberately, and start again; for a valuable site, migrate credentials without deleting the data.
The installer keeps reappearing
This usually means Drupal is seeing a new or empty sites volume, or it is connecting to a new empty database. Check that the Compose project directory and service names are unchanged, inspect the volumes with docker volume ls, and ensure you did not run docker compose down -v. Also verify that the PostgreSQL volume is mounted at /var/lib/postgresql/data.
A module reports a missing extension
Read the module’s requirements, then build a custom Drupal image that includes the extension. Recreating the stock image will not add software that the image does not contain.
Files or configuration are not writable
Inspect the Drupal logs and the mounted paths. The sites volume must be writable by the web process, and custom bind mounts must have permissions that allow the container to read and write as required. Named volumes avoid many host filesystem permission surprises during an initial setup.
Quick Recap
When this Compose setup is appropriate
- Local development: Use the supplied file to create a repeatable Drupal and PostgreSQL environment without installing PHP or a database on the host.
- Training and demonstrations: SQLite can reduce setup to one container when the database server itself is not part of what you are demonstrating.
- Pre-production testing: PostgreSQL or MySQL in a second service is closer to a typical multi-service deployment and exposes networking, credentials, and persistence issues early.
- Public production hosting: Harden passwords, protect the Docker host, configure backups and monitoring, pin and review image versions, use TLS through an appropriate front end, and follow Drupal’s production security and update practices. The simple file is a starting point, not a complete production architecture.
Final verification checklist
docker --versionanddocker compose versionreturn successfully.- Both services are running in
docker compose ps. - The Drupal page opens on the host port you selected.
- The installer uses PostgreSQL with database host
postgres. - The database name, user, and password match the PostgreSQL environment.
- Named volumes exist for Drupal paths and PostgreSQL data.
docker compose downfollowed bydocker compose up -dreturns to the installed site.- You have a separate backup plan for the database and Drupal files before treating the environment as important.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

