Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHP and Symfony Apps As Standalone Binaries

PHP and Symfony Apps As Standalone Binaries

Distributing PHP applications is quite complicated. For instance, to run a Symfony project in production, a web server, the PHP engine, and the appropriate PHP extensions need to be installed. Their versions and configurations must be compatible with the app. Because PHP is an interpreted language, the application source code must also be available. Composer dependencies as well... and things are even more difficult if some of them are private.

Of course, these days, containers can help. But what if we could make things even simpler: a single distributable binary that's self-executing? Download a single file, give it the execution bit, and type "./my-app php-server": boom! Your Symfony application is up and running, served over HTTP/3 with a valid TLS certificate! If you also want to distribute CLI commands written in PHP, we've got your back.

Thanks to the latest features of FrankenPHP, the dream is now a reality! Let's discover how to ship PHP and Symfony applications as standalone binaries, web server, PHP included!

Kévin Dunglas

December 08, 2023
Tweet

More Decks by Kévin Dunglas

Other Decks in Programming

Transcript

  1. Symfony Apps
    As Standalone
    Binaries
    The story of a successful
    experimentation

    View full-size slide

  2. Kévin Dunglas:
    ➔ CEO @ Les-Tilleuls.coop
    ➔ FrankenPHP and API Platform creator
    ➔ Symfony Core Team
    ➔ PHP and Go contributor
    @dunglas

    View full-size slide

  3. 70+ API, Web and Cloud Experts
    ➔ Dev, consultancy and hosting
    ➔ 100% employee-owned co-op ✊
    ➔ API Platform creators 🕷
    ➔ Symfony backers 🎼
    ➔ PHP Foundation advisory board 🐘
    [email protected] 💌

    View full-size slide

  4. Prerequisites to Deploy a Symfony App in Prod
    ➔ A web server
    (NGINX, Caddy, Apache…)
    ➔ A PHP executor
    PHP-FPM (most likely)
    ➔ Usually, some PHP extensions
    curl, pdo_*, gd, apcu...
    ➔ Usually, a database server
    PostgreSQL, MariaDB, MongoDB…

    View full-size slide

  5. Deploying your Symfony App
    When your server(s) is ready, you need to:
    ➔ Get the latest stable version of app
    source code
    ➔ Install the dependencies of your project:
    composer install --no-dev -a

    View full-size slide

  6. The Good Old Days of FTP 👴

    View full-size slide

  7. FTP/SCP, Shared Hosting 👴
    ➔ Easy (and usually cheap)
    ➔ No (or limited) control over
    ● PHP version
    ● Extensions
    ● Config
    ➔ Not possible to install custom extra
    services (Redis…)

    View full-size slide

  8. Your Own Servers (or Computer)
    ➔ Full control over everything
    ➔ You are on your own for everything
    ● Initial setup
    ● Security
    ● Performance
    ● Upgrades…

    View full-size slide

  9. Platforms as a Service

    View full-size slide

  10. Platforms As a Service
    ➔ git push
    and done…
    ➔ … as long as your app is pretty
    standard
    ➔ The platform installs, maintains and
    optimizes the infrastructure
    (hardware and software) for you

    View full-size slide

  11. Symfony & Docker

    View full-size slide

  12. The Symfony Docker skeleton
    ➔ Skeleton with good defaults
    ➔ Full control over everything
    ➔ Extensible
    ➔ Same environment in dev, in your CI
    pipelines and in prod
    ➔ You still need servers
    ➔ Can be hard in prod (knowledge!)

    View full-size slide

  13. Let’s Experiment!

    View full-size slide

  14. Reminders: PHP
    ➔ PHP is an interpreted language (script)
    ➔ The CPU cannot execute directly a PHP
    script
    ➔ An interpreter is needed
    ➔ The official interpreter (php-src) is
    written in C
    ➔ The PHP interpreter doesn’t contain a
    (production-grade) web server

    View full-size slide

  15. Reminders: dynamic vs static linking
    ➔ The PHP interpreter and its extensions
    depends on C and C++ libraries (ex:
    libcurl, OpenSSL, libsodium)
    ➔ These libraries can be linked with the
    interpreter dynamically or statically
    ➔ Dynamic linking: the library is a shared
    external binary (.so file on Linux) loaded
    at runtime by programs. Typical for PHP.
    ➔ Static linking: the library is embedded in
    the program binary. Hard to do for PHP.
    © Tatiana Fernández

    View full-size slide

  16. Our Goals
    ➔ Distribute PHP apps as standalone
    binaries
    ➔ The binary must work without a local
    PHP or web server
    ➔ The end-user shouldn’t even know the
    app is written in PHP
    ➔ SO the binary must contain
    ● A web server
    ● The PHP executor
    ● The PHP code and the assets
    ● The vendors
    ➔ The binary must be statically compiled,
    with no external dependencies

    View full-size slide

  17. ➔ Written in Go 😻
    ● Can be compiled statically
    ● Can embed static C libraries, such as
    PHP
    ● Can embed arbitraries files, such as
    our app, assets and vendors
    ➔ Extensible with modules
    ➔ Prod ready
    ● HTTP/2, HTTP/3, Early Hints…
    ● Automatic HTTPS
    ⚔ Our Weapons: The Caddy Web Server

    View full-size slide

  18. ⚔ Our Weapons: FrankenPHP 1.0 🎉
    New website, created by Laury Sorriaux.

    View full-size slide

  19. ➔ Standalone Go library
    ➔ Embed the official PHP executor in
    your Go programs
    ➔ New SAPI for Go net/http
    ➔ Caddy module using the library
    ➔ Unique features:
    ● Worker mode ⚡
    ● 103 Early Hints
    ● Extensible in Go
    ⚔ Our Weapons: FrankenPHP

    View full-size slide

  20. ⚔ More About FrankenPHP

    View full-size slide

  21. ➔ Compile statically:
    ● PHP (CLI, FPM, libphp…)
    ● Its dependencies (pkgconfig…)
    ● Most PHP extensions (curl, gd, apcu,
    intl…)
    ● Most PHP extensions dependencies
    (libxml, libpng…) 🔁
    ➔ CLI tool, written in PHP
    ➔ Entirely configurable
    ➔ Used by FrankenPHP, Native PHP, Laravel
    Laravel Herd…
    ⚔ Our Weapons: static-php-cli

    View full-size slide

  22. ⚔ Our Weapons: static-php-cli

    View full-size slide

  23. ⚔ Our Weapons: Go embed Package

    View full-size slide

  24. Summary
    We’ll create a static binary containing:
    ➔ A web server (Caddy)
    ➔ PHP (and its dependencies)
    ➔ The extensions we need (and their
    dependencies)
    ➔ FrankenPHP
    ➔ Our PHP code
    ➔ The dependencies of our PHP code
    ➔ Our assets

    View full-size slide

  25. I’ve Done The Wiring Work For You!

    View full-size slide

  26. Prepare your app
    $ echo APP_ENV=prod > .env.local
    $ echo APP_DEBUG=0 >> .env.local
    $ rm -Rf .git/, tests/
    $ composer install --no-dev -a
    $ composer dump-env prod

    View full-size slide

  27. $ git clone \
    https://github.com/dunglas/frankenphp
    $ cd frankenphp
    $ EMBED=/path/to/my/sfapp \
    ./build-static.sh
    # 🎉🎉🎉
    $ cp dist/frankenphp-- my-app
    Build (Linux and Mac)!

    View full-size slide

  28. Run
    Web server (HTTPS, HTTP/3…)
    $ ./my-app php-server
    --domain=example.com
    Worker mode (HTTPS, HTTP/3)
    $ ./my-app php-server -w public/index.php
    CLI
    $ ./my-app php-cli bin/console app:my-cmd

    View full-size slide

  29. Ready-Made Dockerfile
    FROM dunglas/frankenphp:static-builder
    # Copy your app
    WORKDIR /go/src/app/dist/app
    COPY . .
    # Build the static binary, be sure to select only the
    PHP extensions you want
    WORKDIR /go/src/app/
    RUN EMBED=dist/app/ \
    PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
    ./build-static.sh

    View full-size slide

  30. More Options
    Environment variables:
    ➔ PHP_VERSION: the PHP version to use
    (currently, 8.2 or 8.3)
    ➔ PHP_EXTENSIONS: PHP extensions to build
    (build only what you need to reduce the
    binary size)
    ➔ PHP_EXTENSIONS_LIB: extra libs (ex:
    libjpeg for GD) to build
    ➔ FRANKENPHP_VERSION: the FrankenPHP
    version to use

    View full-size slide

  31. Any questions?
    Come at our booth!
    Thanks!
    frankenphp.dev
    @dunglas

    View full-size slide