Deploy PHP application

I am trying to deploy a PHP-application to Fly.io, but with no luck. I just get the “Hello from Fly”-message.

I used to have a Heroku instance, added the fly.toml and I get no error messages when doing fly deploy.

My repository is here? GitHub - vih/vih-viggo-standalone: Stand alone app for getting calendar items from Viggo

Is it because I am missing a Dockerfile? - and how should the file look to be able to deploy this very simple PHP-app?

Via the Builders and Fly documentation:

Per the App Configuration documentation, build.image is the builder option to skip the building process by specifying an image that has already been built.

[build]
  image = "flyio/hellofly:latest"

So, in your configuration, Fly is ignoring your application entirely and deploying flyio/hellofly:latest which is the source of the “Hello from Fly” message you’re seeing.

I haven’t used the buildpacks before, but as I understand it from the documentation, your configuration is almost correct. The changes that are required are:

  1. Remove the build.image
  2. Select a php buildpack
  3. Select a builder that is compatible with the php buildpack

I found paketo-buildpacks/php, which says in the README that it’s compatible with 2 builders: paketobuildpacks/builder-jammy-full and paketobuildpacks/builder:full. Unfortunately, PHP 7.4 is at end of life, so it’s not supported by either of these builders: you’ll need to upgrade your app to PHP 8 if you wish to use these builders. The good news is, based on a quick scan of your code; there’s no reason you need PHP 7.4, so if you modify your composer.json to allow for PHP 8, it should work fine:

    "require": {
-        "php": "7.4.*",
+        "php": "~8",

Run composer update php to apply those changes to your composer.lock. Then you can update your fly.toml to use the correct builder and buildpack:

[build]
- builder = "paketobuildpacks/builder:base"
+ builder = "paketobuildpacks/builder:full"
- buildpacks = ["gcr.io/paketo-buildpacks/nodejs"]
+ buildpacks = ["gcr.io/paketo-buildpacks/php"]
- image = "flyio/hellofly:latest"
-  [build.args]
-   PHP_VERSION = "7.4"
-   NODE_VERSION = "14"

You’ll also need to change from port 80 to port 8080. Your final fly.toml will be:

# fly.toml file generated for vih-kalendersiden on 2022-12-09T08:21:47+01:00

app = "vih-kalendersiden"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[build]
  builder = "paketobuildpacks/builder-jammy-full"
  buildpacks = ["gcr.io/paketo-buildpacks/php"]

[env]
APP_URL = "https://vih-kalendersiden.fly.dev"
PORT = 8080

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 8080

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

The final change is to delete the Procfile, then run fly deploy and your application should be good to go :slight_smile: I have submitted this all as a Pull Request to your repository: fix: Build application for Fly deployment using buildpack by shrink · Pull Request #9 · vih/vih-viggo-standalone · GitHub

1 Like

Hi there!

I have checked the solution and can verify it works. Thanks @shrink for contributing!
If you have any other questions, don’t hesitate to reach out.

Johannes

Thanks @shrink. It was a really good starting point.

Do you know how I can enable php-extensions in the buildpack? One of my dependencies has some dependencies that is not satisfied.

Paketo Buildpack for Composer Install 0.2.0
  Executing build process
  Building new layer /layers/paketo-buildpacks_composer-install/composer-packages
  Running 'composer install'
exit status 2
    Installing dependencies from lock file
    Verifying lock file contents can be installed on current platform.
    Your lock file does not contain a compatible set of packages. Please run composer update.
    
      Problem 1
        - kigkonsult/icalcreator is locked to version v2.41.71 and an update of this package was not requested.
        - kigkonsult/icalcreator v2.41.71 requires ext-zlib * -> it is missing from your system. Install or enable PHP's zlib extension.
    
    To enable extensions, verify that they are enabled in your .ini files:
        - /layers/paketo-buildpacks_composer-install/composer-php-ini/composer-php.ini
        - /layers/paketo-buildpacks_php-dist/php/etc/buildpack.ini
        - /layers/paketo-buildpacks_php-dist/php/etc/php.ini
        - /layers/paketo-buildpacks_php-dist/php/etc/buildpack.ini
        - /layers/paketo-buildpacks_php-dist/php/etc/php.ini
    You can also run `php --ini` in a terminal to see which files are used by PHP in CLI mode.
    Alternatively, you can run Composer with `--ignore-platform-req=ext-zlib` to temporarily ignore these required extensions.
ERROR: failed to build: exit status 1
Error failed to fetch an image or build from source: executing lifecycle: failed with status code: 51
1 Like

Reviewing the documentation, it looks like, unfortunately, zlib isn’t supported within this buildpack and there is no option to install custom extensions. The package you depend on (kigkonsult/icalcreator) didn’t introduce the dependency on zlib until version 2.41.39 (earlier this year), so you could downgrade to 2.41.30. Alternatively, you could bypass the dependency check and cross your fingers that the code you’re relying on doesn’t actually need zlib: I couldn’t find any apparent reason it would be required… to do that you could add the build argument suggested in the error message, e.g:

[build]
  builder = "paketobuildpacks/builder:full"
  buildpacks = ["gcr.io/paketo-buildpacks/php"]
  [build.args]
    BP_COMPOSER_INSTALL_OPTIONS = "--ignore-platform-req=ext-zlib"

If downgrading to version 2.41.30 isn’t an option, and ignoring the dependency on zlib isn’t an option, then I think (without experience of buildpacks) the next best option would be to use your own Dockerfile instead of relying on a buildpack. If you don’t have Docker experience, that might be a painful switch but it would be straight forward if you know what you’re doing with Docker :slight_smile:

Wow. @shrink thank you so much for your help.

I downgraded the dependency and was able to get it built now.

However, I keep getting this error, which I suppose is openssl not properly setup.

PHP Warning: file_get_contents(): Unable to find the wrapper "https" - did you forget to enable it when you configured PHP? in /workspace/index.php on line 129

I have a ´require` in my composer set to:

    "require": {
        "php": "~8",
        "ext-openssl": "*"
     }

As here: vih-viggo-standalone/composer.json at master · vih/vih-viggo-standalone · GitHub

So it should setup the extension requirement as per How to Build PHP Apps with Paketo Buildpacks - Paketo Buildpacks

But maybe there is something that i do not understand properly.

According to this comment on GitHub the openssl extension is not automatically available through the composer require behaviour due to an issue that is yet to be fixed. However, according to this issue there is a workaround whereby you create your own .ini file and enable the extension there:

diff --git a/.php.ini.d/extension.ini b/.php.ini.d/extension.ini
new file mode 100644
index 0000000..cb58b9c
--- /dev/null
+++ b/.php.ini.d/extension.ini
@@ -0,0 +1 @@
+extension=openssl.so

I ran a quick test and it seems to work – /calendar/proxy/vih loads, no error!

1 Like

@shrink. Thank you so much. You totally saved my weekend. Have a really good day.

1 Like

Hello guys, I’m having a problem trying to deploy a PHP application. I use the composer also in the project. I tried to use the example spoken by @shrink. However, it did not work.

The first form I tried to use the configuration in the fly.tom.

[Build]
     Builder = "PakeTobuildPacks/Builder-Jammy-Full"
     buildpacks = ["gcr.io/paketo-buildpacks/php"]

However, it presents the error below.

Paketo Buildpack for Composer Install 0.3.3
  Executing build process
  Building new layer /layers/paketo-buildpacks_composer-install/composer-packages
  Running 'composer config'
  
  Running 'composer install'
exit status 2
    Installing dependencies from lock file
    Verifying lock file contents can be installed on current platform.
    Your lock file does not contain a compatible set of packages. Please run composer update.

      Problem 1
        - dompdf/dompdf is locked to version v0.8.3 and an update of this package was not requested.
        - dompdf/dompdf v0.8.3 requires ext-mbstring * -> it is missing from your system. Install or enable PHP's mbstring extension.
      Problem 2
        - phenx/php-font-lib is locked to version 0.5.4 and an update of this package was not requested.
        - phenx/php-font-lib 0.5.4 requires ext-mbstring * -> it is missing from your system. Install or enable PHP's mbstring extension.

    To enable extensions, verify that they are enabled in your .ini files:
        - /layers/paketo-buildpacks_composer-install/composer-php-ini/composer-php.ini
        - /layers/paketo-buildpacks_php-dist/php/etc/buildpack.ini
        - /layers/paketo-buildpacks_php-dist/php/etc/php.ini
        - /layers/paketo-buildpacks_php-dist/php/etc/buildpack.ini
        - /layers/paketo-buildpacks_php-dist/php/etc/php.ini
    You can also run `php --ini` in a terminal to see which files are used by PHP in CLI mode.
    Alternatively, you can run Composer with `--ignore-platform-req=ext-mbstring` to temporarily ignore these required extensions.
ERROR: failed to build: exit status 1
Error failed to fetch an image or build from source: executing lifecycle: failed with status code: 51

Follow the settings of my Fly.Tom file

# fly.toml file generated for sig-example on 2023-02-16T15:21:58-03:00

app = "sig-example"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

#[build]
#    builder = "paketobuildpacks/builder-jammy-full"
#    buildpacks = ["gcr.io/paketo-buildpacks/php"]

[env]
APP_URL = "https://sig-example.fly.dev"
PORT = 8080

[[services]]
    http_checks = []
    internal_port = 8080
    processes = ["app"]
    protocol = "tcp"
    script_checks = []
    [services.concurrency]
        hard_limit = 25
        soft_limit = 20
        type = "connections"

    [[services.ports]]
        force_https = true
        handlers = ["http"]
        port = 80
    
    [[services.ports]]
        handlers = ["tls", "http"]
        port = 443
    
    [[services.tcp_checks]]
        grace_period = "1s"
        interval = "15s"
        restart_limit = 0
        timeout = "2s"

Then I tried to deploy configuring a dockerfile file and commenting on the build part in Fly.tom

My dockerfile

# the PHP version from the user (wherever `flyctl launch` is run)
# Valid version values are PHP 8.1+
ARG PHP_VERSION=8.1
#FROM serversideup/php:${PHP_VERSION}-fpm-apache as base
#FROM fideloper/fly-laravel:${PHP_VERSION} as base
FROM serversideup/php:${PHP_VERSION}-fpm-apache as base

# PHP_VERSION needs to be repeated here
# See https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact
ARG PHP_VERSION

LABEL fly_launch_runtime="PHP Application"

# copy application code, skipping files based on .dockerignore
COPY . /var/www/html

RUN composer install --optimize-autoloader --no-dev \
    && chown -R www-data:www-data /var/www/html \
    && cp .fly/entrypoint.sh /entrypoint \
    && chmod +x /entrypoint

RUN mkdir /app

RUN mkdir -p  /app
WORKDIR /app
COPY . .
COPY --from=base /var/www/html/vendor /app/vendor

# From our base container created above, we
# create our final image, adding in static
# assets that we generated above
FROM base

EXPOSE 8080

ENTRYPOINT ["/entrypoint"]

This is the error when I try to deploy using Dockerfile.

Error failed to fetch an image or build from source: error building: failed to solve with frontend dockerfile.v0: failed to solve with frontend gateway.v0: rpc error: code = Unknown desc
 = failed to create LLB definition: circular dependency detected on stage: base

I tried to deploy these two ways, but neither funned. Can anybody help me?

That’s the key problem that we’ll need to resolve: you do not have (ext-)mbstring enabled. Fortunately, it’s included with the buildpack so you should be able to enable it using your composer.json by adding it to the require block. For example…

"require": {
    "ext-mbstring": "*"
 }

If you continue to experience problems after making that change, please share a link to your repository or share a copy of your composer.json here :slight_smile:

Thank you for your attention @shrink. I did what you told me, but the mistake still persisted. Follow the link from the repository, it has the composer file.

{
  "require": {
    "php": "~8.1",
    "phpmailer/phpmailer": "^6.0",
    "tburry/pquery": "^1.1",
    "picqer/php-barcode-generator": "^2.0.1",
    "dompdf/dompdf": "^1.0",
    "bacon/bacon-qr-code": "^2.0",
    "phprtflite/phprtflite": "^1.3",
    "firebase/php-jwt": "^5.0",
    "linfo/linfo": "^4.0",
    "adianti/plugins": "dev-master",
    "adianti/pdfdesigner": "dev-master",
    "pablodalloglio/ole": "dev-master",
    "pablodalloglio/spreadsheet_excel_writer": "dev-master",
    "pablodalloglio/fpdf": "dev-master",
    "ext-mbstring": "*",
    "ext-pdo_sqlite": "*",
    "ext-pdo_mysql": "*"
  },
  "config": {
    "preferred-install": {
      "*": "dist"
    }
  }
}

Hi @lordjackson, welcome to Fly.io!

Fly.io’s scanner already creates the necessary files for Laravel applications( a framework for PHP applications ) to get up and running in Fly! So one quick way you may get your PHP application running with Fly.io is to allow Fly.io to auto-generate “config” files for you, by making it think you have a Laravel application setup. To do so, you’ll have to have an artisan file in your root directory–its fine even if it’s empty–You can read more about the reason why you’d need the artisan file in our docs here.

Try out the steps below, and see if you can get your application deployed!

  1. Create an artisan file in your project directory with touch artisan
  2. Run the command fly launch- this should generate several files like fly.toml, and Laravel specific config file/folder: Dockerfile and a.fly directory
  3. Then, simply update your Dockerfile to just cater to PHP application, likeso:
# syntax = docker/dockerfile:experimental

# Default to PHP 8.2, but we attempt to match
# the PHP version from the user (wherever `flyctl launch` is run)
# Valid version values are PHP 7.4+
ARG PHP_VERSION=8.2
FROM fideloper/fly-laravel:${PHP_VERSION} 

# PHP_VERSION needs to be repeated here
# See https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact
ARG PHP_VERSION

LABEL fly_launch_runtime="laravel"

# copy application code, skipping files based on .dockerignore
COPY . /var/www/html

RUN composer install --optimize-autoloader --no-dev \
    && mkdir -p storage/logs \
    && php artisan optimize:clear \
    && chown -R www-data:www-data /var/www/html \
    && cp .fly/entrypoint.sh /entrypoint \
    && chmod +x /entrypoint


EXPOSE 8080

ENTRYPOINT ["/entrypoint"]
  1. Finally, deploy! fly deploy
1 Like

Thanks for your attention @kathrynannetan, I took the test you referred to me. Presented the following error below.

Unfortunately it didn’t work

WARN Failed to start remote builder heartbeat: failed building options: failed probing "personal": context deadline exceeded
Error failed to fetch an image or build from source: failed building options: failed probing "personal": context deadline exceeded

Hi @lordjackson ! Can you check the health of your fly environment with the following command: fly doctor? This thread might also help: Eror "Failed to start remote builder heartbeat: failed building options: failed probing "personal": context deadline exceeded"

Hi @lordjackson. @kathrynannetan is a Fly employee and I’m not, so I would trust their recommendations over mine, but if you decide to give the Paketo buildpack approach another try, the example in Deploy PHP application - #7 by shrink is not limited to just openssl.so. You can add other extensions into .php.ini.d/extension.ini as well. For example, if you want both openssl and mbstring, that ini file file could contain:

extension=openssl.so
extension=mbstring.so

Hi @Alex21!

There’s more than one way to deploy a PHP application with Fly.io, just as there is more than one path to a solution to this thread—Your recommendation is 200% just as valid as mine :raised_hands: That’s a great point out!

Also, all recommendations that lead to solving our community members’ post is as valid as any other, it builds our community, and are all very much appreciated. Thank you for sharing your solution!

1 Like

I’m trying to deploy a simple hello world PHP app :

<?php
echo 'Hello World';
?>

Dockerfile

FROM php:7.4-cli
RUN mkdir myProject
WORKDIR myProject
COPY . .
EXPOSE 8080
ENTRYPOINT ["php", "index.php"]
[error]Health check on port 8080 has failed. Your app is not responding properly. Services exposed on ports [80, 443] will have intermittent failures until the health check passes
curl --head https://myProject.fly.dev
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to myProject.fly.dev:443 

Hey @anjanesh !

Not sure if you’ve gotten anywhere since you posted this, but the container you’re using (php:7.4-cli) doesn’t have a web server in it, so it won’t run PHP in a way that can respond to web requests.

You may have better luck using the official php image that includes apache. (php:7.4-apache - Docker )

That container will expect code to exist in /var/www/html (IIRC). You won’t need to use the EXPOSE keyword, but note that Apache will run on port 80, so the [services] portion of your fly.toml will need to use internal port 80 instead of 8080.

Ok, let me try using php:7.4-apache - but for the time being, on some other posts I found that this works.

[build]
  builder = "paketobuildpacks/builder-jammy-full"
  buildpacks = ["gcr.io/paketo-buildpacks/php"]

Is there an updated PHP build pack that you can suggest @shrink?

Tried to use this against a new deployment and running into a timeout error:

WARNING: image with reference "[gcr.io/paketo-buildpacks/php](https://gcr.io/paketo-buildpacks/php)" was found but does not match the specified platform: wanted linux/amd64, actual: linux

failed to fetch an image or build from source: failed to write image to the following tags: [pack.local/builder/7a6f7162756361636f66:latest: loading image "pack.local/builder/7a6f7162756361636f66:latest". first error: embedded daemon response: max depth exceeded]