Deploy a PHP + MySQL Site on Managed Cloud Hosting, Step by Step
Host a classic PHP app the modern way: containerise it, then pair it with a managed PostgreSQL database, or run MySQL yourself as a container app when your code needs it. Custom domain, TLS, and backups included. Start free with $5 trial credit.
PHP and MySQL power a huge share of the web, from WordPress and Laravel to countless custom dashboards. This guide takes a PHP app from your machine to a live URL on managed cloud hosting, and pairs it with a database. On the database, you get two honest options, and this guide walks both so you can pick the one that fits your app.
Your two database options, stated plainly
- The managed path is PostgreSQL. The platform runs it, stores it, and backs it up, and PHP talks to it through the standard
pdo_pgsqldriver. If your code uses PDO or a framework like Laravel, moving from MySQL to PostgreSQL is usually a configuration change, not a rewrite. This is the path we recommend for most apps. - If your app specifically needs MySQL, the most transparent option is to run MySQL yourself as a container app with a persistent volume. You operate it, you back it up, and your PHP app connects to it over the project's private network.
This guide shows both. Start with the PHP container, which is identical either way.
Step 1: A production Dockerfile for PHP
Your app runs as a Docker image that listens on port 8080 (where the platform routes traffic) and runs as a non-root user. This image builds on the official PHP + Apache image and installs both database drivers, so the same image works with PostgreSQL or MySQL:
FROM php:8.3-apache
# PostgreSQL and MySQL PDO drivers so the app can talk to either database
RUN apt-get update \
&& apt-get install -y --no-install-recommends libpq-dev \
&& docker-php-ext-install pdo pdo_pgsql pdo_mysql \
&& rm -rf /var/lib/apt/lists/*
# Apache listens on 8080 (the port the platform routes to) instead of 80
RUN sed -i 's/80/8080/g' /etc/apache2/ports.conf /etc/apache2/sites-available/000-default.conf
COPY --chown=www-data:www-data ./src /var/www/html
USER www-data
EXPOSE 8080Build and run it locally first to be sure it serves your app:
docker build -t my-php-app .
docker run --rm -p 8080:8080 my-php-app
# open http://localhost:8080Step 2: Deploy through Cloud Studio
Open Cloud Studio, pick Application, give it a name, and choose public access. Your app boots on a *.alawadi.cloud subdomain with TLS in place. To ship your own image and get push-to-deploy, create a private registry and connect your Git repository through GitHub OIDC, exactly as in the 5-minute deploy guide. Every push to main then builds and deploys automatically.
Step 3, option A: Add a managed PostgreSQL database
From the Databases tab, choose New database, pick Postgres, a name, and resources. The database is created inside your project's isolated environment in seconds. On the database page, the Link to container action injects the connection string into your app as the DATABASE_URL environment variable, so you never paste a password anywhere.
Read it in PHP with PDO:
<?php
// The platform injects DATABASE_URL when you link the database to the app
$url = parse_url(getenv('DATABASE_URL'));
$dsn = sprintf(
'pgsql:host=%s;port=%d;dbname=%s',
$url['host'],
$url['port'] ?? 5432,
ltrim($url['path'], '/')
);
$pdo = new PDO($dsn, $url['user'], $url['pass'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$version = $pdo->query('SELECT version()')->fetchColumn();
echo "Connected to: " . $version;The platform handles operation, storage, and backups for this database. Details are in the managed databases docs.
Step 3, option B: Run MySQL as your own container app
If your app must use MySQL, deploy the official mysql:8 image as a second Application in the same project. Give it a name like db, and attach a persistent volume so its data survives restarts and redeploys. Set the credentials as environment variables on the MySQL container (its root password and initial database), and set matching values on your PHP app so it can connect.
Apps in the same project reach each other over a private network, so your PHP app connects to the MySQL container by the name you gave it:
<?php
$pdo = new PDO(
'mysql:host=' . getenv('DB_HOST') . ';dbname=' . getenv('DB_NAME'),
getenv('DB_USER'),
getenv('DB_PASS'),
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);Because you run this database yourself, you also back it up yourself: schedule a mysqldump and ship it to object storage, following the nightly backup tutorial.
Step 4: Your own domain
The *.alawadi.cloud subdomain is great for testing, but your site deserves its own address. On the app's page, add your custom domain and point the DNS record the portal shows you. The TLS certificate is managed automatically.
Step 5: Backups you can trust
Two layers protect your data:
- The platform takes daily encrypted backups of persistent volumes, stored off-server for 14 days, plus full weekly backups kept for 8 weeks.
- You keep your own copy in an S3-compatible bucket at $0.04 per GB-month with free egress. And the golden rule holds: a backup you have never restored is not a backup.
What it costs, and how to start
Billing is pay-as-you-go against a USD-credit ledger, with every service as its own clear line item and optional USD, SYP, AED, or JOD display. Estimate your managed PHP and MySQL setup with the pricing calculator, sign in with Google, and claim the $5 trial credit in the portal with no card. Prepaid vouchers priced in SYP are the only live top-up rail; card and cryptocurrency top-ups are not currently available.
FAQ
Can I move my MySQL app to PostgreSQL easily?
Often, yes. If your code uses PDO or a framework's query builder, the change is mostly in configuration and a few SQL differences. Apps with a lot of hand-written MySQL-specific SQL take more work, and for those, running MySQL as your own container is the honest choice.
Where do I store secrets like the database password?
Set them as environment variables on the service in the portal, not baked into the image. For the managed database, the connection string is injected for you when you link it.
Does this work for WordPress or Laravel?
Laravel supports PostgreSQL out of the box, so the managed path fits it well. WordPress expects MySQL, so run MySQL as your own container as shown in option B. Another question? Open a support ticket in the portal or email [email protected].
The company behind alawadi.cloud
The company building an Arabic-first cloud platform, from the physical servers up to the developer experience.