Running a Symfony app on a VPS with Docker and FrankenPHP
Published on December 18, 2024
In this article, we will demonstrate how to set up a Symfony application on a VPS powered by FrankenPHP. The entire process will rely on a single command: docker
.
Prerequisites
You must have root access to a dedicated server. In this tutorial, we use an Ubuntu 24.04.1 LTS server as the base. The setup begins from scratch after installing this minimal Ubuntu distribution (with the latest minor fixes applied). To verify the base distribution setup, run the following command:
lsb_release -a
The output should be:
Distributor ID: Ubuntu
Description: Ubuntu 24.04.1 LTS
Release: 24.04
Codename: noble
Step 1: first login and server update
Access the server. In this example, we log in with the “ubuntu” user. Then, you can either switch to the root account by using sudo -i
or run the commands with sudo
as a prefix. In this tutorial, all commands are executed after switching to the root account with sudo -i
.
Step 2: server update
A good practice when accessing a fresh server is to update it. There may be many global and security fixes since the last release, to do so, run (and reboot):
apt-get update & apt-get upgrade
reboot
Step 3: Docker installation
In the following steps, Docker is the only command-line tool we need. To install it, you can follow the official guide. Below is a quick summary of the installation steps:
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
cat /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
At this point, the docker
command should be available. To verify that everything has been installed correctly, you can run the Docker “Hello World” container with the following command:
docker run hello-world
If everything is set up correctly, you should see the following output:
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image, which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more advanced, you can run an interactive Ubuntu container with the following command:
docker run -it ubuntu bash
Discover more features, share images, and automate workflows by creating a free Docker ID: https://hub.docker.com/. For additional examples and ideas, visit the official Docker documentation.
The first thing to do is to download the last FrankenPHP Docker image.
docker pull dunglas/frankenphp
To check if there are any running instances, you can use the following command:
docker ps --filter "ancestor=dunglas/frankenphp"
Step 4: Symfony project installation
We could use the default Symfony skeleton, but let’s opt for something more complete than a simple "Hello World" page. For example, we can use the MicroSymfony application template.
To create a new application based on this template, run the following command:
docker run --rm -it -v $PWD:/app composer:latest create-project strangebuzz/microsymfony && cd microsymfony
This command creates a new microsymfony
directory and installs all the PHP dependencies using Composer.
To run this application with FrankenPHP, you need to install the FrankenPHP runtime:
docker run --rm -it -v $PWD:/app composer:latest require runtime/frankenphp-symfony
Ensure that nothing is currently running on port 80 by executing:
sudo lsof -i :80
The command should return nothing, confirming that the port is free to use.
Our application is now ready, and we can serve it by running the following command:
docker run \
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
-e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \
-e SERVER_NAME=frankenphp.microsymfony.ovh \
-e APP_ENV=prod \
-e APP_DEBUG=0 \
-v $PWD:/app \
-p 80:80 -p 443:443 \
-d \
dunglas/frankenphp
In this example, the frankenphp.microsymfony.ovh
domain is used. FrankenPHP relies on this parameter to generate an SSL certificate, allowing the website to support the HTTPS protocol.
Run the following command:
docker ps
The output should look something like this:
CONTAINER ID 2c4f8b7229aa
IMAGE dunglas/frankenphp
COMMAND "docker-php-entrypoint ..."
CREATED 16 hours ago
STATUS Up 16 hours (healthy)
PORTS 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 443/udp, 2019/tcp
NAMES relaxed_haslett
Great! We now have a running and healthy container.
Step 5 : access the application
Now that we have a successfully running container, let’s access it to check Symfony and PHP. To access the container with an interactive shell, run the following command:
docker exec -it $(docker ps --filter "ancestor=dunglas/frankenphp" --format "{{.Names}}") /bin/bash
Alternatively, you can directly use the container's name. Replace relaxed_haslett
with the name of your container from the previous docker ps
command:
docker exec -it relaxed_haslett /bin/bash
You should now be logged into the container, with a prompt like this:
root@30482311dc06:/app
To test PHP, run:
php -v
The output should be similar to this:
PHP 8.4.1 (cli) (built: Nov 21 2024 17:57:47) (ZTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.4.1, Copyright (c) Zend Technologies
Next, test Symfony by running:
bin/console --version
The output should look like this (depending on the latest MicroSymfony tag, currently 7.2.1 as of writing this article):
Symfony 7.2.1 (env: prod, debug: false)
Everything is now set up and this site should be accessible. You can visit it using the domain we set up.
In the footer, we can see:
Since FrankenPHP is the PHP SAPI, if we access the regular MicroSymfony website at https://microsymfony.ovh/, we should see:
This is because it uses PHP-FPM in this case. In the Twig template, the PHP SAPI is retrieved via a global parameter like this:
return [
'sf_version' => Kernel::VERSION,
'php_version' => \PHP_VERSION,
'php_sapi' => \PHP_SAPI,
];
That’s it! The website is up and running, an SSL certificate has been generated, and the FrankenPHP workers are ready to process HTTP requests.
Conclusion
We’ve explored one of the many solutions for deploying a website online. Of course, this solution may not be suitable for every project, so it should be used with care. If you prefer to focus on developing your application, we can take care of hosting your PHP/Symfony application. Whether for small or large projects, we handle it all. Contact us to learn more.