Drupal hosting on AWS: when a self-managed build makes sense
Self-hosting Drupal on AWS means your team, or a partner you hire, designs, builds and runs every layer of the stack inside your own AWS accounts: the compute that serves PHP, the managed or self-run database, the file storage, the caching edge, the backups and the release pipeline. Drupal itself is free to use. Drupal and the contributed files hosted on Drupal.org that derive from it are licensed under the GNU General Public License, version 2 or later (GPL-2.0-or-later), and there is no paid edition of Drupal. Your cost therefore sits in infrastructure, build effort and ongoing operations, not in a license fee, so the comparison with a hosted Drupal service should be made on those terms.
Drupal runs on Apache, Nginx and other web servers, with MariaDB, MySQL, PostgreSQL or SQLite as the database, according to the Drupal.org system requirements page. Which web server and database you choose is only the first decision. AWS itself offers several ways to run the same application, and none of them removes the need to design the web tier, the database tier, the shared file path and the cache layer yourself. Confirm with your security and compliance owners which of these pieces must stay in your accounts, which region and network boundaries apply, and who holds the on-call duty for patching the PHP runtime and the operating system. A self-managed build makes sense when your organization already has AWS operating discipline and needs control over those choices. If you do not have that capacity, the same questions still apply, and they will be answered by a partner or by hires you have not yet budgeted for.
Compute and database options and when each fits
This table compares the main AWS compute and database choices for self-managed Drupal, with the operational load each one places on your team. Read each row against your Drupal release, your PHP version and your team's ability to patch servers, because those factors usually decide the fit. The main takeaway is that managed databases reduce routine work but still require you to confirm engine versions and Drupal compatibility before you commit.
| Option | Fit for Drupal | Load on your team | Confirm before choosing |
|---|---|---|---|
| EC2 with an Auto Scaling group | Teams that want full control of the web server, PHP-FPM and OS packages, with a fixed image pipeline | High: you own OS patching, PHP updates, image baking and scaling rules | PHP version support for your Drupal release on the system requirements page and your web server choice |
| ECS containers | Composer-built Drupal images with stateless PHP containers and external file and database services | Medium: you own image rebuilds for security releases and task definitions for cron | Image build approach and how cron and drush jobs run as separate tasks |
| EKS containers | Teams already operating Kubernetes with multiple Drupal sites or other workloads on the same cluster | High: you own cluster upgrades, ingress, autoscaling and Kubernetes skills | Whether your platform team can support cluster lifecycle alongside Drupal releases |
| Managed PaaS-style hosting on AWS | Smaller estates that accept platform limits in exchange for less infrastructure work | Low to medium: the provider handles much of the runtime, but you still own Drupal code and updates | Which PHP versions, extensions, cron options and file system access the platform allows |
| Amazon RDS or Aurora for MySQL or MariaDB | Standard Drupal databases where the team wants managed backups, patching windows and failover options | Low to medium: you own engine version upgrades, parameter groups and restore testing | Engine and version support against the Drupal database requirements, plus any MySQL-specific contributed modules |
| Amazon RDS or Aurora for PostgreSQL | Sites that standardize on PostgreSQL and need its feature set or pg_trgm for search | Low to medium: you own major version upgrades and extension compatibility | Confirm pg_trgm and other extensions are available on the chosen engine and version |
| Self-run database on EC2 | Teams with strong database administration skills who need custom engine settings or unsupported configurations | High: you own backups, replication, failover, patching and monitoring | Backup and restore tests you can run, and who is on call for database incidents |
How s3fs and CloudFront handle files and cache purging
The s3fs module lets Drupal store public files in an S3 bucket through a stream wrapper, so file fields and image styles write to object storage rather than to local disk. Web nodes then need no shared file volume for public content. Confirm the exact settings and their names in the module documentation for your Drupal version, because configuration keys and bucket options change between releases.
- Stream wrapper scheme: Public files are addressed through the module's scheme, so the path stored in the database is a bucket key. Plan the migration of existing file references before cutover.
- Bucket read model: Decide whether public objects are readable directly from S3 or only through CloudFront. Direct public read is simpler, but it exposes the bucket endpoint and complicates a later move to origin access control.
- Object metadata: Set cache-control metadata on uploads so CloudFront and browsers cache images for a planned duration. Confirm which headers the module sets and which must come from the bucket or a CloudFront response headers policy.
- Image derivatives: Styles are generated on demand and written to the bucket. Check that derivatives are written correctly and that first requests during launch do not overload the origin.
- Existing file migration: Copy the public files directory to the bucket with a tested sync, then verify file counts and sample URLs before enabling the module on production.
Confirm bucket policy, metadata and derivative behavior in a staging environment before cutover.
Private files should never be reachable by guessing a URL. In a standard Drupal site, private files are served by Drupal after an access check. On AWS, that means either a separate private bucket with public access blocked, or a short-lived signed URL issued only after Drupal confirms the user may see the file. Confirm which of these modes your s3fs version supports and how it handles private paths.
- Separate bucket or prefix: Keep private objects where a misconfigured public policy on the public bucket cannot expose them. Block public access at the account or bucket level.
- Access checks through Drupal: Route downloads through a controller that checks entity and file access, then either streams the file or redirects to a signed URL.
- Signed URL lifetime: Short expiry limits how long a shared link works, but users who open a page late may hit errors. Choose an expiry that matches typical session length and test it.
- CloudFront signing: If CloudFront fronts private content, decide between signed URLs for single objects and signed cookies for a set of files. Confirm key management and rotation against AWS documentation.
- Access logging: Log access decisions in Drupal and enable access logging on the bucket or distribution, so downloads can be reviewed later.
Check the private file path, the response for anonymous users and the expiry behavior with test accounts before go-live.
CloudFront usually sits in front of the Drupal site for pages and in front of the S3 bucket for files. The two origins are routed by path pattern on one distribution or split across two. Confirm the current behavior and origin settings in AWS documentation, since the console options and recommended policies change over time.
- Origin access control: Restrict the bucket so only the distribution can read it. This keeps the bucket private while public files still load through CloudFront. Confirm how your s3fs configuration builds URLs when a custom domain is used, because the domain changes the origin setup.
- Path-based behaviors: Send the public files path to the bucket origin with long cache times, and send other paths to the Drupal origin with cache rules that respect cookies.
- Forwarded cookies and headers: Forward the session cookie only where authenticated pages need it, and forward the Host header that Drupal uses for trusted host checks. Forwarding more than needed fragments the cache.
- Edge rules for pages: Anonymous pages can be cached at the edge. Authenticated responses should bypass the edge cache or vary by cookie. Confirm that Drupal sends accurate max-age and Vary headers.
- Compression and TLS: Enable compression for text assets and require TLS between CloudFront and the origin.
Test an anonymous page, a logged-in page and an image URL, and inspect response headers to confirm which layer served each one.
Edge caches keep pages long enough to be fast, so editors need changes to reach the public site promptly. Drupal attaches cache tags to rendered output for entities, views and blocks. A CDN integration module can use those tags to decide which cached pages to purge. CloudFront invalidates by path, so tag-based purging needs a mapping layer that translates tags into paths. Confirm which module and version provides that mapping and how it stores it.
- Tag-to-path mapping: Confirm how the module records which URLs carry each tag, and whether that record grows with page count.
- Invalidation scope: Broad invalidations clear more pages but may be slower and count against quotas. Narrow invalidations are more precise but may need many requests for a heavily tagged entity. Confirm current quotas and charges on AWS.
- Purge latency: Invalidations take time to propagate across edge locations. Plan for that delay in editorial workflows and measure it on a staging distribution.
- Queued purging: Queuing purges during bulk imports reduces API pressure but adds delay. Decide which operations should purge immediately.
- Failure handling: If a purge request fails, pages stay stale until expiry. Monitor purge errors and set a maximum age that limits the damage.
Measure the time from saving content to seeing the public change on a staging distribution before editors depend on it.
Setup sequence for Drupal on AWS
This sequence takes a Drupal site from an empty AWS account to a tested production release, with a verification check at each step so the team knows a layer works before the next one depends on it. It is written for platform engineers and the partner or internal team that will own the environment after launch.
Define accounts and the VPC layout
Separate development, staging and production into distinct AWS accounts or tightly scoped environments, then create a VPC with public subnets for the load balancer and private subnets for compute, the database and cache. Decide who holds administrative roles, how logging is centralized and where the state for infrastructure as code lives. Done means a test instance in a private subnet can reach the internet only through the intended egress path, and a security review of the network diagram has been signed off by the client's security owner.
Provision the database and set parameters
Create the managed MySQL, MariaDB or PostgreSQL instance in private subnets with encryption at rest, a dedicated Drupal user with least privilege, and parameter settings that match the Drupal version's database minimums and the chosen engine. Confirm backup retention and maintenance windows with the client, then load a copy of the existing database or a fresh install to confirm connectivity. Done means Drush can connect from a compute host, and a point-in-time restore has been run into a scratch instance to prove the backup settings work.
Build compute and the load balancer
Choose the compute model that fits the team's operating skills, such as EC2 instances in an Auto Scaling group or containers, and place it behind an Application Load Balancer with health checks on a lightweight Drupal-aware path. Install the web server and PHP runtime, set the PHP version to one the target Drupal release supports, and configure the instance profile so it can read only the secrets and buckets it needs. Done means the health check passes on every instance, and a test request through the load balancer returns the Drupal front page over HTTPS.
Move settings.php and trusted host patterns out of the repository
Keep database credentials, the hash salt and the trusted_host_patterns list in environment variables or AWS Secrets Manager and load them through an environment-specific include, so the repository holds no secrets. Set trusted host patterns to the exact production, staging and load balancer hostnames. Done means a request with an unexpected Host header is rejected, and a secrets scan of the repository finds no credentials.
Configure s3fs and CloudFront for files and caching
Point the public and private file paths at S3 using the s3fs module, with the private path kept out of public URLs and bucket policies restricted to the Drupal instance role. Place CloudFront in front of the site, set cache behavior for authenticated and anonymous traffic, and wire cache tag purging so content edits invalidate the right objects. Done means an uploaded image is served from the distribution, a private file returns an access denial when requested directly, and an edit to a test node purges its cached page within the expected flow.
Schedule cron and run queue workers
Move cron out of web requests into a scheduled job or a dedicated worker, and run queue workers as separate processes with their own restart policy so background tasks do not compete with page rendering. Record which host or task runs each job so failures are visible. Done means cron runs on schedule without triggering from page views, a queued item is processed by a worker, and a deliberately failed job appears in the logs and alerting.
Prove backup and restore before launch
Back up the database and the S3 file buckets on the schedule agreed with the client, including versioning or replication for files, and document who can trigger a restore. Then restore into an isolated environment and check that the site loads, logins work and recent files are present. Done means a timed restore has been completed and its result is written into the runbook with the gaps, if any, that the client accepts.
Release from staging to production
Build the codebase with Composer in the pipeline, deploy it to staging, run database updates and configuration import, and test critical journeys including login, search and content editing. Repeat the same artifact in production during an approved window, with a rollback plan that names the previous build and the database restore point. Done means production passes the same smoke tests as staging, the cache purge check succeeds on live content, and the release record is stored with the runbook.
Security and operational risks to design for
Drupal on AWS carries risk in a few predictable places: credentials, storage exposure, network paths, patch timing, traffic filtering and the logs that show what happened. The cards below cover each one, with the checks to run in your own account before go-live.
Secrets outside code
Database passwords, the Drupal hash salt, SMTP credentials and S3 keys belong in AWS Secrets Manager or Systems Manager Parameter Store, read at runtime through an IAM role attached to the compute. Keep settings.php free of literal credentials and confirm that no secret appears in the Git history, container images or CI logs. Ask who can read each secret and how rotation is tested against a running site.
Bucket policy and public access
An S3 bucket holding private files or exports must block public access at the account and bucket level, and the s3fs configuration should use a role with the narrowest prefix it needs. Public files should live under a separate, deliberately exposed path. Check that the bucket is not reachable through old presigned URLs or a permissive policy added during troubleshooting, and that versioning and access logging are on.
Network segmentation
Place the web tier, the database and the cache in private subnets with security groups that allow only the ports each tier needs. Only the load balancer or CloudFront origin path should accept public traffic. Confirm that the database has no public endpoint, that outbound access from PHP workers is limited to the services Drupal needs (for example, the update and Composer mirrors), and that administrative access uses a bastion or session manager rather than open SSH.
Patching tied to the release calendar
Drupal publishes bugfix releases on the first Wednesday of each month and security releases on the third Wednesday. Build your patch process around those dates: a rebuilt image or artifact, a test run against staging, then a production release with database updates and configuration import. Decide in advance who approves an out-of-cycle patch, and confirm that AWS-managed components such as the database engine and the operating system image have their own maintenance windows that you track.
WAF and login protection
A web application firewall in front of the origin can block common attack patterns and rate-limit login attempts, but its managed rule sets need tuning for Drupal's admin paths, forms and file uploads, or they will cause false positives. Pair it with Drupal-side controls such as flood protection and strong account policies. Confirm the rule mode for each rule group, who reviews blocked requests, and how a rule change is tested before it reaches production.
Logging and retention
Collect web server access logs, Drupal's watchdog output, load balancer and CloudFront logs, and AWS CloudTrail events in a central location that the application team cannot silently alter. Set retention periods with your compliance owner rather than accepting defaults, and test that you can search logs during an incident. Confirm which fields are masked so that personal data and session tokens do not end up in log storage.
How to design backups and restores for files and database
A Drupal backup is three things, and a restore only works when all three line up: the database, the file store in S3 and the code build that reads them. The database holds content, configuration, users and cache metadata. The S3 bucket holds public and private files referenced by that database. The code build, usually a Composer-built artifact pinned to a release, must match the database schema and the configuration the site was exported with. Before you choose any AWS feature, decide which of these three you can rebuild from source control and which you must recover from a copy, because that split determines what you back up at all.
For the database, the first decision is whether you use a managed engine such as Amazon RDS or Aurora with point-in-time recovery, or self-manage MySQL, MariaDB or PostgreSQL on EC2. Managed point-in-time recovery lets you restore to a timestamp inside the retention window, which is useful after a bad content import or a faulty update that ran database updates. Confirm the retention period, whether restores create a new instance (so the site must be repointed through settings.php or environment variables), and whether automated snapshots are copied to a second region. For S3, enable bucket versioning so an overwritten or deleted file can be recovered, then add lifecycle rules that expire noncurrent versions after a period your records policy allows. Versioning without a lifecycle rule will grow storage cost quietly.
The business must set the recovery point objective and recovery time objective for each site, and the outline's testing rule applies to both. A restore that has never been run against current data is a guess. Schedule a restore into a separate account or environment at a regular interval, then check that Drupal boots, that files resolve through the file system configuration and that drush status reports the expected database. Record how long each step took and compare it with what the business agreed. Ask your AWS partner or internal team to confirm which backups are covered by the account's backup plan and who holds the keys for encrypted snapshots, because a restore is blocked if those permissions are missing.
Limits to confirm before committing to an AWS design
Several constraints decide whether a self-managed Drupal design on AWS holds up over its lifetime: the PHP and database versions the target release accepts, the modules that connect Drupal to S3 and a CDN, the Drupal 10 end-of-life date, the cost model in your account, and whether your team can respond to incidents. Confirm each one before the architecture is fixed, because each changes compute, database and operations choices.
Supported PHP and database versions
The target Drupal release sets the minimum PHP runtime, and that runtime sets the compute image you build. Drupal 11 requires PHP 8.3 or later and Drupal 12 requires PHP 8.5 or later, so a platform image pinned to an older PHP line will need rebuilding before the upgrade. Check the database engine and version against the Drupal system requirements too, and confirm that the managed MySQL or PostgreSQL version you plan to use is one that Drupal supports for that release.
Module compatibility with S3 and CDN
File storage on S3 through s3fs and cache tag purging at CloudFront depend on contributed modules that must match your Drupal core version. Confirm that the release of each module supports your target core, that its maintenance status is current, and that it works with the CloudFront purge method you plan to use. Test private file access and image derivative handling on a staging copy, since those paths are where S3 setups most often break.
Drupal 10 end of life
Drupal 10 reaches end of life on December 9, 2026, according to the Drupal core release schedule. A design that runs Drupal 10 past that date will need an upgrade or a paid extended support arrangement. Ask whether the AWS platform can run Drupal 11 and then Drupal 12 without a rebuild of the hosting stack, and plan the upgrade window around the bugfix and security release cadence.
Cost model in your account
AWS charges for compute, managed database storage and I/O, S3 storage and requests, CloudFront transfer, backups and data egress, and these figures differ by region and by how the platform scales. Ask for a cost model built in your own account and billing structure, with separate estimates for steady traffic and peak events. Also ask what recurs each month and what changes after a Drupal upgrade or a larger content library.
On-call staffing for operations
A Drupal site on AWS needs someone to respond when cron stalls, a queue backs up, the database fails over, or a security release lands on a Wednesday. Confirm who holds the pager, how many people share it, and whether they can apply a security patch within your own change process. If the team cannot staff that rota, a support retainer or a managed arrangement changes the operating model and should be priced into the design.
Questions teams ask before hiring help for Drupal on AWS
What drives the cost of a self-managed Drupal deployment on AWS?
The biggest drivers are how many environments you need, how much traffic and content the site carries, and how many integrations sit around it. Each AWS service adds configuration, monitoring and cost: compute (EC2, ECS or EKS), a managed MySQL or PostgreSQL database, S3 for public and private files, CloudFront with cache tag purging, backups and logging. Your cost splits into one-time work (architecture, Terraform or CloudFormation, build pipelines, load testing, cutover) and recurring cloud spend plus patching and support. Ask any quote to itemize AWS resources, who owns the account, and which parts are one-time versus recurring.
How long does a Drupal on AWS build take?
Duration depends on scope more than on Drupal itself. A single site with one environment, a standard database and S3 file storage is a much smaller job than a multisite estate with separate staging, CloudFront cache purging, SSO and a migration from Drupal 7. Plan for time in four blocks: architecture and account setup, infrastructure as code and pipelines, application configuration and testing, then cutover and handover. Ask for a timeline tied to written deliverables and to the environments in scope, not a generic estimate.
What must our team provide before a hosting project starts?
Most delays come from missing decisions rather than missing code. Before work starts, the client usually needs to provide:
- AWS accounts, organizational structure, and the IAM roles or permission boundaries the build team may use
- A network plan covering VPC layout, CIDR ranges, DNS zones, certificates and any VPN or private connectivity
- Decisions on content and access, including which files are public, which are private, retention rules, and who can administer the site
- The current Drupal version, PHP version, database engine, and a list of contributed modules and integrations
Ask the partner to confirm this list in writing as part of scoping.
Can an internal team build Drupal on AWS without outside help?
Yes, if the team already runs AWS in production, has Drupal developers who understand Composer-based builds, and has someone who can own the security model. The hard parts are rarely the first deployment. They are cache invalidation through CloudFront, file handling through s3fs, database backups and restore testing, and keeping patching on the release schedule. Compare your team's experience in each area against the scope you need. A partner is most useful for fixed-scope design reviews, a first build, or a handover that your own staff can operate afterward.
What recurs after launch and what is one-time work?
One-time work includes architecture, infrastructure build, pipeline setup, migration, load testing and cutover. Recurring work includes AWS usage charges, backups and periodic restore tests, monitoring and alert handling, Drupal core and contributed module updates, and PHP upgrades. Drupal's bugfix releases come out on the first Wednesday of each month and security releases on the third Wednesday, so a patching routine should be planned around that calendar. Ask whether support is a retainer, what response expectations it includes, and who handles emergency security releases.
How do we ask for a fixed-scope quote for Drupal on AWS?
Send a written scope that names the environments, the AWS services in use, the Drupal version and PHP version, the integrations, the number of sites, the data migration, and the acceptance tests. Ask the provider to list deliverables, assumptions, client responsibilities and exclusions, and to state the timeline for each phase. Request that AWS costs be shown separately from labor, and that any cloud resources the partner creates are documented and transferred to your account. DeployOpen plans most engagements as fixed scope, with the agreed scope, deliverables and timeline written down before work starts, and quotes follow from that scope.
What security and compliance questions should we settle before the build?
Settle the security model early because it shapes the architecture. Decide how secrets are stored and rotated, how the database and S3 buckets are encrypted and restricted, how CloudFront and origin access are controlled, how administrative access is logged, and how backups are kept separate from production. Drupal's security advisories are published by the Drupal Security Team with CVE identifiers, so your patch process should track them. DeployOpen prepares systems, controls and evidence for compliance assessments, but independent auditors and certification bodies issue any audit reports or certifications.
Official Drupal sources for hosting decisions
Before you choose EC2, ECS or EKS, Aurora or RDS, confirm the platform floor for the Drupal release you plan to run. The Drupal.org system requirements page lists the supported web servers (Apache, Nginx and others) and database engines (MariaDB, MySQL, PostgreSQL or SQLite). Those lists decide whether your AWS database service and your AMI or container base image can run the stack without a custom build. Ask your architect to record the exact database versions the release supports, because managed engine versions on AWS move on their own schedule and may not match the minimums in the requirements.
The PHP requirements page sets the runtime floor for the image or AMI you build. According to that page, Drupal 10 requires PHP 8.1 or later, Drupal 11 requires PHP 8.3 or later and Drupal 12 requires PHP 8.5 or later. That means the PHP version becomes a dependency you pin in your build pipeline, not a default you inherit from an operating system package. Confirm which PHP version your chosen base image ships, and whether your contributed modules and hosting tooling support it, before you commit to a launch date.
The core release schedule is the document that drives your AWS operating calendar. According to the schedule, bugfix releases arrive on the first Wednesday of each month and security releases on the third Wednesday, and Drupal 10 reaches end of life on December 9, 2026, with Drupal 12 scheduled for the week of December 7, 2026. Build your image rebuild and patch windows around those Wednesdays, and check whether your planned Drupal major version will still be supported for the life of the infrastructure, since a long-lived EC2 or EKS design can outlast the release it was built for.
How DeployOpen scopes and delivers Drupal hosting on AWS
DeployOpen plans, builds, documents and supports self-hosted open-source platforms inside the client's own cloud accounts, so the AWS environment for Drupal is designed, owned and operated in your infrastructure. Each engagement starts from a written scope that sets out compute, data services, file storage, caching and backup decisions before any build work begins.
How we scope
- Written scope lists the AWS accounts, regions, compute option and Drupal release the environment will run.
- Scope records the database engine, file storage approach, CloudFront caching design and cache tag purging requirements.
- Engagements are fixed-scope, so deliverables, timelines and responsibilities are agreed in writing before work starts.
How we build
- Build covers infrastructure as code, Composer-based code delivery, and environment-specific settings kept outside the repository.
- Files on S3 through s3fs, CloudFront distribution and cache tag purging are configured and tested against your Drupal site.
- Backup design for database, files and configuration is implemented and restore procedures are exercised before handover.
How we hand over
- Handover includes architecture documentation, runbooks for deployments, scaling, failover and restores, and access records.
- Security testing scope and hardening notes for the AWS account, network paths, secrets and Drupal settings are delivered with the build.
- Your team receives training sessions on operating the stack, with the upgrade path for Drupal core and contributed modules documented.
How we support
- Ongoing support, upgrades and continuous testing are available as retainers that follow the written scope after handover.
- Retainer work can track Drupal security releases, which are published on Wednesday windows, and plan rebuilds of the platform.
- Confirm response expectations, coverage hours and included services in writing before choosing a support arrangement.

