Skip to main content

Deploy a PHP Stack (Apache + MySQL)

A minimal PHP app that counts page visits in MySQL, deployed as a Stack. Unlike the Python and Node tutorials (which inject a single connectionString), this one wires individual fields — host, user, password, database — which is the idiomatic shape for PHP/mysqli.

Result: visiting the app shows Hello from Kuploy Stacks! Visits: N, incrementing on each refresh.

1. The app

index.php
index.php
<?php
// Each value is injected by a separate stack connection.
$db = new mysqli(
getenv('DB_HOST'),
getenv('DB_USER'),
getenv('DB_PASSWORD'),
getenv('DB_NAME')
);
$db->query("CREATE TABLE IF NOT EXISTS visits (count INT)");
$db->query("INSERT INTO visits (count) SELECT 0 WHERE NOT EXISTS (SELECT 1 FROM visits)");
$db->query("UPDATE visits SET count = count + 1");
$n = $db->query("SELECT count FROM visits")->fetch_row()[0];
echo "Hello from Kuploy Stacks! Visits: {$n}";

Grab this from kuploy/examples (subdir php-mysql), or create the files yourself and push them to a Git repo. First complete the tutorial Prerequisites — a connected Git provider and a build registry — then connect the repo and set the build path as in Deploy Your First App.

2. Choose a build method

See Build Methods for the full list.

Recommended for this example. The repo includes a Dockerfile:

Dockerfile
FROM php:8.3-apache
RUN docker-php-ext-install mysqli
COPY . /var/www/html/
EXPOSE 80

When you create the app, set Build Type → Dockerfile, enter Dockerfile in the Docker File field (required; relative to the build path), and use port 80.

3. Create the services

In your project's environment:

  1. Create Service → Application named web. The Set up your application wizard opens — walk the steps in order (or close it and use the service's tabs manually):
    • Source — point it at your Git repo (set Build Path php-mysql if using kuploy/examples).
    • Build — pick the Build Type from above (Dockerfile for this example).
    • Network — set the port to 80; add a domain if you want it public.
    • Registry — select the registry from the prerequisites; without it the build has nowhere to push and the deploy fails with Registry required. (Skipped automatically for Docker-image sources or single-server deploys.)
    • Deploy — stays disabled until source and registry are set. Don't deploy it yet.
  2. Create Service → Database → MySQL named db; note the database name, user, and password you set. The internal host is the service's app name (mysql://<user>:<password>@<db-app-name>:3306/<database>, on the db's General tab; see Databases) — the connections below inject host / user / password / database individually.

4. Group them into a stack

  1. Environment toolbar → Stacks → Create stack, name it visits, open it.
  2. Add component → add web, then db.

5. Connect (four fields)

Open Connect and create four connections, all with provider db → consumer web:

Source fieldEnv var name
hostDB_HOST
userDB_USER
passwordDB_PASSWORD
databaseDB_NAME

Each connection injects one value; together they give mysqli everything it needs. host resolves to the database's in-cluster service name, so traffic never leaves your private network.

6. Deploy

Click Deploy stackdb deploys before web (it's the provider on all four connections). Open the app's domain and refresh; the counter climbs.

Verify the injection

The web service's Environment tab shows a managed block with DB_HOST, DB_USER, DB_PASSWORD, and DB_NAME resolved.

What you learned

  • Connections can inject a full connectionString or individual fields (host/user/password/database) — use whatever your stack expects.
  • Multiple connections from the same provider are fine; the platform still deploys db first.

Next: the same app in Python or Node.js.