Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →The quickest repeatable way to run Drupal locally is to define Drupal and PostgreSQL in a Compose file, start both containers, and finish Drupal’s browser installer at http://localhost:8080. In the installer, select PostgreSQL and use postgres as the database host—not localhost. The hostname is the PostgreSQL service name inside the Compose network.
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
This guide shows a working setup, explains which data survives container recreation, covers Drupal’s database alternatives, and gives recovery steps for the failures most likely to occur during installation.
As an Amazon Associate I earn from qualifying purchases.
What you need before installing
Install Docker Desktop, or install Docker Engine, the Docker CLI, and the Docker Compose plugin. Docker documents both installation paths. Docker Desktop is generally the simpler choice on Windows and macOS; a Linux host can use the Engine, CLI, and Compose plugin directly.
Drupal’s documentation recommends Linux or a similar operating system for hosting and describes Windows as supported for development environments. The containers isolate most host-specific details, but Docker itself still must be running before you start the project.
#1 Best Overall
- A working Docker installation with the
docker composecommand. - A terminal opened in a new, empty project directory.
- Enough disk space for Drupal core, extensions, uploaded media, generated files, and backups. Drupal.org states that core files require about 100 MB (2025), but total site storage is not fixed and depends on the site.
- At least PHP 8.3 or a higher PHP 8 version and a minimum PHP memory size of 64 MB are listed by Drupal.org (2025). The official Drupal container supplies PHP for the application; these figures are useful when evaluating custom images or a non-containerized companion service.
Choose a directory that you can back up. The Compose file, any bind-mounted Drupal files, and the PostgreSQL data volume together define your installation.
Create the Compose project
1. Make a project directory
- Create and enter a directory, for example
drupal-compose. - Create a file named
compose.yamlin that directory.
Compose reads the file in the current directory when you run commands such as docker compose up. Keeping the file under version control makes the service definitions reproducible, but do not commit production passwords or other secrets.
2. Start with the official two-service definition
The following arrangement is adapted from the Docker Official Image example. It exposes Drupal on port 8080 and puts both services on the project’s default Compose network.
services:
drupal:
image: drupal:10-apache
ports:
- "8080:80"
volumes:
- /var/www/html/modules
- /var/www/html/profiles
- /var/www/html/themes
- /var/www/html/sites
restart: always
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: example
restart: always
The four Drupal volume entries are container paths. They allow image initialization to populate Drupal’s site directories and allow those files to remain available when the Drupal container is recreated. The short example does not define persistent storage for PostgreSQL, so it is suitable for learning but should not be treated as a durable site.
3. Add an explicit PostgreSQL volume for a durable local site
Before installing content you care about, add a named volume at PostgreSQL’s data directory and declare it at the end of the file:
services:
drupal:
image: drupal:10-apache
ports:
- "8080:80"
volumes:
- /var/www/html/modules
- /var/www/html/profiles
- /var/www/html/themes
- /var/www/html/sites
restart: always
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: example
volumes:
- postgres_data:/var/lib/postgresql/data
restart: always
volumes:
postgres_data:
This named volume is separate from the Drupal file mounts. It holds PostgreSQL’s database files when the database container is stopped or recreated. A container restart is not a backup: protect the volume with a backup plan appropriate to your environment.
Recommended Free Tools
The password in this example is intentionally simple so the browser setup is easy to follow. Replace it before using the project beyond a throwaway demonstration, and keep the replacement out of publicly shared Compose files.
Launch Drupal and PostgreSQL
- In the directory containing
compose.yaml, rundocker compose up. - Wait for both images to download and for initialization to complete. The first launch can take longer because Docker must pull the Drupal and PostgreSQL images and PostgreSQL must create its initial cluster.
- Open
http://localhost:8080in a browser. Docker’s official instructions describe visiting that address, orhttp://host-ip:8080when connecting through another host.
Keep the terminal attached during the first start so you can see errors. When you are satisfied that the services start correctly, stop the foreground process with Ctrl+C and relaunch in the background with docker compose up -d. The containers’ restart policy is always, so Docker will attempt to restart them after a failure or daemon restart.
To see the project’s state, run docker compose ps. To inspect startup messages, use docker compose logs drupal or docker compose logs postgres. Add -f to follow a log stream while reproducing a problem.
Complete Drupal’s browser installer
Choose the installation profile and language
Open the site at port 8080 and follow Drupal’s installer. Select the language and installation profile requested by your project. The profile determines which initial configuration Drupal creates; it does not change the Compose networking described below.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsRank #3
Enter the PostgreSQL connection details
When Drupal asks for a database, select PostgreSQL and enter these values for the Compose file above:
| Drupal field | Value | Why |
|---|---|---|
| Database type | PostgreSQL | The database service uses the postgres:16 image. |
| Database name | postgres |
The PostgreSQL image creates this default database for the initial setup when no other database name is specified. |
| Database username | postgres |
This is the default administrative database user created by the image. |
| Database password | example |
It matches POSTGRES_PASSWORD in compose.yaml. |
| Database host | postgres |
This is the Compose service name and the DNS name visible to Drupal on the project network. |
| Database port | Leave the default PostgreSQL port unless you changed the container configuration | Drupal connects to the database over the internal Compose network, not through the host’s published web port. |
Do not enter localhost as the database host. Inside the Drupal container, localhost refers to the Drupal container itself. The name postgres resolves to the separate PostgreSQL container because it matches the service key.
If you change the service key, use the new key as the host. Likewise, if you change the password or create a different database user, the values in Drupal must match the database environment and initialization state.
Set the site and administrator information
Continue through the form for the site name, site email, administrator username, administrator password, and administrator email. Drupal’s Composer documentation describes this web setup as collecting database credentials, an administrator name, and basic site information. Use an administrator password that is unique to this site.
Submit the installer and wait for Drupal to create its schema and initial configuration. A successful completion redirects you into the new site. If the form reports a database connection error, stop and check the troubleshooting section rather than repeatedly submitting unchanged values.
Rank #4
How persistence works
Drupal code, themes, modules, and site files
The example mounts /var/www/html/modules, /var/www/html/profiles, /var/www/html/themes, and /var/www/html/sites. These mounts are intended to let initialization populate the directories and retain site files when the container is replaced. They cover important Drupal-managed content, including the sites tree where site-specific settings and uploaded files are commonly kept.
They do not turn every path in the image into an independently backed-up host directory. Treat the Compose definition and the mounted data as separate assets: preserve the YAML file, inspect what Docker created for the anonymous Drupal volumes, and back up the site files you need to restore.
PostgreSQL data
The explicit postgres_data volume is the durable location for PostgreSQL’s data directory. Running docker compose stop or recreating a container does not remove a named volume. Conversely, a command that removes the project’s volumes can delete the database, so read the confirmation carefully before using a destructive cleanup command.
Free tools Windows power users keep installed
One-click scans. No signup required.
A volume is not a logical database backup. For a recoverable site, schedule database dumps and copy Drupal’s files to storage outside the Docker host. Test restoration before relying on the backup.
What happens after a restart
With the named PostgreSQL volume and the Drupal mounts in place, docker compose restart restarts the services without intentionally deleting their data. If the Docker daemon or host reboots, restart: always instructs Docker to bring the containers back when the daemon is available. You still need to verify that the volume is attached and that the site opens after a host-level restart.
Best Value
Database choices: PostgreSQL, MySQL, or SQLite
Drupal supports MariaDB, MySQL, PostgreSQL, and SQLite. The container image can use SQLite without a second database container. MySQL and PostgreSQL require a separate database service whose credentials and service-name hostname agree with Drupal’s installer.
| Choice | Containers | Operational complexity | Best fit | Development-to-production similarity |
|---|---|---|---|---|
| SQLite | One Drupal container | Lowest for a disposable local demo; no database service to initialize | A quick experiment or temporary prototype | Lower when production uses a server database |
| PostgreSQL | Drupal plus PostgreSQL | Requires a second service, credentials, a database volume, and database backups | A multi-service development stack or a PostgreSQL production target | High when production also uses PostgreSQL |
| MySQL or MariaDB | Drupal plus the selected database service | Comparable multi-service setup; use matching image variables and a service-name host | Projects that must match existing MySQL-compatible hosting | High when production uses the same engine |
For this walkthrough, PostgreSQL is used because the supplied Compose example defines it explicitly. If you switch engines, do not keep PostgreSQL’s credentials or hostname assumptions: select the corresponding Drupal database type and configure the second service according to that image’s documented environment variables.
Common installation problems and fixes
The browser cannot open port 8080
- Confirm Docker is running and execute
docker compose ps. - Check the Drupal logs with
docker compose logs drupal. - Make sure another host process is not already using port 8080. Change the left side of
"8080:80"to an unused host port, such as"8081:80", then open the matching URL. - When connecting from another machine, use the Docker host’s IP address and the published port rather than that remote machine’s
localhost.
Drupal says it cannot connect to PostgreSQL
- Use
postgresfor the database host. Do not uselocalhostor the host machine’s IP address for this internal connection. - Check that the database service is running with
docker compose psand inspectdocker compose logs postgres. - Confirm the installer password exactly matches
POSTGRES_PASSWORD. - Allow PostgreSQL to finish first-time initialization, then reload the installer. The service may be running while its initial database setup is still in progress.
- If you changed
POSTGRES_PASSWORDafter the named volume was initialized, the existing database keeps its original credentials. Changing the environment value alone does not reset an already initialized database.
The site worked, then the database disappeared
Check whether the PostgreSQL service had a named volume before the container was removed. The short official example does not include one. Add postgres_data:/var/lib/postgresql/data, declare postgres_data under the top-level volumes key, and restore from a dump if the original database files were deleted.
A Drupal module reports a missing PHP extension
The Drupal image does not include every PHP extension that modules may require. When a module needs an absent extension, build a custom image with a Dockerfile that starts FROM drupal:10-apache and installs the required extension, then change the Compose service to build that image. Identify the module’s exact requirement before modifying the image; installing unrelated extensions increases maintenance work.
Changes appear to vanish after container recreation
Determine where the change was written. Files under the mounted Drupal paths and data under postgres_data are designed to persist. Files written elsewhere in the container filesystem can disappear when the container is replaced. Keep custom code in a deliberate bind mount or image build, and keep database content in PostgreSQL rather than in temporary container layers.
Safe lifecycle commands
| Goal | Command | Effect |
|---|---|---|
| Start in the foreground | docker compose up |
Creates or starts services and displays live logs. |
| Start in the background | docker compose up -d |
Creates or starts services and returns control of the terminal. |
| View service status | docker compose ps |
Shows whether the Drupal and PostgreSQL containers are running. |
| Follow Drupal logs | docker compose logs -f drupal |
Streams web-container output while you diagnose startup or request errors. |
| Follow PostgreSQL logs | docker compose logs -f postgres |
Streams database initialization and connection output. |
| Stop services without removing them | docker compose stop |
Stops containers while leaving the project resources and volumes in place. |
| Restart services | docker compose restart |
Restarts the existing containers without intentionally deleting volumes. |
| Remove the project | docker compose down |
Removes the project’s containers and network; named volumes are retained unless you explicitly request volume removal. |
Use destructive volume-removal options only when you intentionally want a clean installation. Removing the PostgreSQL volume removes the database stored there.
When this setup is appropriate
This Compose project is well suited to local development, module and theme work, demonstrations, and reproducible test environments. It gives Drupal a predictable database hostname and lets you start the stack with one command.
It is not, by itself, a production hardening plan. Before exposing a site publicly, replace example credentials, review filesystem permissions, protect administrator access, configure backups, decide how secrets are supplied, and place the web service behind the HTTPS and network controls required by your hosting environment. The official example’s restart: always setting improves availability after a Docker restart but does not provide monitoring, database replication, or disaster recovery.
Quick Recap
Installation checklist
- Docker Desktop or Docker Engine, CLI, and Compose plugin installed.
compose.yamlsaved in the directory from which you run Compose.- Drupal exposed on a free host port, such as
8080:80. - PostgreSQL service named
postgres. - Drupal volume mounts present for
modules,profiles,themes, andsites. - A named PostgreSQL volume added before creating valuable content.
- Installer database type set to PostgreSQL.
- Installer host set to
postgres, with database name and credentials matching the Compose configuration. - Site administrator details completed and a unique password chosen.
- Backups planned for both the PostgreSQL database and Drupal’s retained files.
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.




