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

Symfony Local Web Server ... reloaded

Symfony Local Web Server ... reloaded

Fabien Potencier

December 06, 2018
Tweet

More Decks by Fabien Potencier

Other Decks in Technology

Transcript

  1. The state of local web servers with Symfony php -S

    Many limitations Docker Might be slow/inconvenient Nginx/Apache Need setup Vagrant Not convenient
  2. My ideal setup? Local Web Server and local files Remote

    services Works well on the major platforms Fast and convenient
  3. PHP built-in server is almost perfect ... but it has

    too many limitations • Only one connection at a time • No HTTP-2 support • No SSL • Does not re-read env vars if they change • Needs some tweaks to make it work with Symfony (special router) • …
  4. …via the new symfony binary • Introduced last week with

    • Binary with no dependencies, not even PHP
 No global Composer changes • Does more than just the Cloud • symfony security:check
 without calls to security.symfony.com • symfony new [--demo] [--full] ...
 to create new Symfony projects • and … https://symfony.com/cloud/download
  5. A Symfony local web server # From your project's directory

    $ symfony server:start # Done! First port available starts at 8000
  6. A Symfony local web server $ symfony server:start -d #

    open in the browser $ symfony open:local # tail the logs $ symfony server:log Start in the background
  7. Some features • No need to be root • Uses

    PHP-FPM whenever possible
 fallbacks to PHP-CGI/php -S (on Windows for instance) • HTTP-2 support out of the box • HTTP Link/pre-load/push support • Works with any PHP project
 Use it for plain HTML websites, Symfony ones, Laravel, Drupal, Magento, … • Fire and forget • Great developer experience…
  8. Why? • Testing a new PHP version or a different

    configuration? • Different projects might need different PHP versions • Most machines have several PHP versions installed
 Think homebrew for instance
  9. Use any of them locally # Change the PHP version

    for the current directory $ echo "7.1" > .php-version # Or any 7.x version? $ echo "7" > .php-version # Done!
  10. Each web server can have its own PHP version #

    Detect the PHP version to use for this directory $ symfony server:start Algorithm (current directory and up) 1/ .php-version? 2/ .symfony.cloud.yaml? 3/ $PATH
  11. The web server uses the “best” backend possible # Detect

    the best possible backend $ symfony server:start Algorithm 1/ PHP-FPM 2/ PHP-CLI (also FastCGI) 3/ php -S
  12. Works also in your terminal # Use the symfony wrapper

    $ symfony php -v $ symfony php -r "echo 'Symfony!';" Algorithm (current directory and up) 1/ .php-version? 2/ .symfony.cloud.yaml? 3/ $PATH
  13. Configure PHP per directory $ symfony php -r "echo ini_get('date.timezone');"

    Europe/Paris # Create a php.ini file at the project's directory $ cat php.ini [Date] date.timezone = Europe/Lisbon $ symfony php -r "echo ini_get('date.timezone');" Europe/Lisbon # Works with the web server as well
  14. # Using the wrapper all the time? # Create a

    copy named php $ cd ~/.symfony/bin/ && cp symfony php # Running php now runs the symfony wrapper! # Works with other PHP binaries $ cd ~/.symfony/bin/ && cp symfony pecl $ cd ~/.symfony/bin/ && cp symfony php-fpm $ cd ~/.symfony/bin/ && cp symfony php-config Want to drink the Kool-Aid?
  15. All the logs are parsed as semantic JSON logs and

    "humanized" From the web server From Symfony From PHP
  16. # Use it even if you are using another web

    server # to get pretty Symfony logs $ symfony server:log --file=/path/to/var/log/dev.log
  17. Why? • More similar to production • Detect mixed-content early

    • Having HTTPS is sometimes a requirement: stripe.js?
  18. How? # From anywhere $ symfony server:ca:install # Done! $

    ls ~/.symfony/certs default.p12 rootCA-key.pem rootCA.pem +Creates a local Certificate Authority +Registers it on your system trust store +Registers it on Firefox +Creates a default certificate
 for localhost/127.0.0.1/...
  19. Why? • Useful when a project behaviour depends on the

    domain name
 Think sub-domains like lisbon2018.symfony.com vs paris2019.symfony.com • No need to remember the ports
 ports can change, is it 8000 or 8001? • Stable endpoint across machines
 Think oauth2 redirect URL for instance • Use “regular” ports: 80 for HTTP and 443 for HTTPS • More similar to the production settings
  20. Optional, independent from the web server # From anywhere $

    symfony proxy:start # Done ...almost! No need to be root
  21. + Nothing to install + No need to mess up

    with your DNS + Same configuration on all platforms + Does not intercept regular traffic
  22. How does it work? $ curl http://127.0.0.1:7080/proxy.pac // Only proxy

    *.wip requests // Configuration file in ~/.symfony/proxy.json function FindProxyForURL (url, host) { if (dnsDomainIs(host, '.wip')) { return 'PROXY 127.0.0.1:7080'; } return 'DIRECT'; }
  23. Optional, independent from the web server # Attach a domain

    to a directory $ symfony proxy:domain:attach symfony.com --dir=~/Code/symfony.com # Start the web server if needed $ symfony server:start -d # Done! https://symfony.com.wip/ is now an “alias” for https://127.0.0.1:8xxx/
  24. Proxy Configuration { "tld": "wip", "port": 7080, "domains": { "*.symfony.com":

    ".../github/symfonycorp/symfony.com", "certif": ".../symfonycorp/certification.symfony.com", "certification": ".../symfonycorp/certification.symfony.com", "demo": "/tmp/demo", "cloud.symfony.com": ".../github/symfonycorp/symfony.com", "symfony.com": ".../github/symfonycorp/symfony.com" } } ~/.symfony/proxy.json .wip or anything else .sf? Wildcard support Multiple domains per directory TLS certificates created on demand
  25. Manage long-running commands # Run yarn in the background $

    symfony run -d yarn encore dev --watch $ symfony server:log $ symfony server:status Web server listening on https://127.0.0.1:8001 Command "/usr/local/bin/yarn encore dev --watch" running with PID 93398 $ symfony server:stop command logs stops the web server
 and the commands
  26. https://demo.com/ Project hosted on SymfonyCloud # Init a project and

    deploy to prod $ symfony project:init # Deploy a cluster of containers PHP, services like DB, TLS, ...
 for the master branch/production env $ symfony deploy # Make it live $ symfony domain:attach demo.com ENV=prod DEBUG=false
  27. https://some-bug-xtf33gy-ombjum625h7iw.eu.s5y.io/ Step 1: Create a branch # Create a new

    Git branch for the code # Deploy a new cluster of containers # Copy data (DB, files, ...) byte to byte $ symfony env:create some-bug # Open the new deployed URL # Exact copy of production $ symfony open:remote # Debug logs $ symfony log # Or switch to dev/debug with $ symfony debug Exact copy of production ENV=prod DEBUG=false
  28. https://demo.com.wip/ Step 2: Run it locally # Attach a local

    domain for fun $ symfony proxy:domain:attach demo.com # Run the local web server $ symfony server:start -d # Open the local website $ symfony open:local ENV=dev DEBUG=true
  29. https://demo.com.wip/ Step 3: Connect the remote services # Open a

    tunnel with the "some-bug" env $ symfony tunnel:open # Refresh the page in the browser # It works! ENV=dev DEBUG=true
  30. .env APP_ENV=dev APP_DEBUG=1 APP_SECRET=67d829bf61dc5f87a73fd814e2c9f629 DATABASE_URL=sqlite:///%kernel.project_dir%/data/database.sqlite MAILER_URL=null://localhost 47 How does it

    work? Environment variables FTW! + The local web server detects the tunnel + It exposes the services as env vars in PHP-FPM + Symfony and SymfonyCloud share the same convention + Symfony reads the env vars + You win!
  31. prod Debugging like a pro With production data But in

    a safe isolated environment Local Web prod DB
  32. prod Debugging like a pro With production data But in

    a safe isolated environment Local Web prod DB some-bug some-bug Web DB symfony env:create Duplicate infra/data Create a local Git branch 1
  33. prod Debugging like a pro With production data But in

    a safe isolated environment Local Web prod DB DATABASE_URL=postgres://127.0.0.1:30002/main symfony tunnel:open 2 some-bug some-bug Web DB symfony env:create Duplicate infra/data Create a local Git branch 1
  34. prod Debugging like a pro With production data But in

    a safe isolated environment Local Web prod DB DATABASE_URL=postgres://127.0.0.1:30002/main symfony tunnel:open 2 some-bug some-bug Web symfony server:start 3 some-bug some-bug Web DB symfony env:create Duplicate infra/data Create a local Git branch 1
  35. prod Debugging like a pro With production data But in

    a safe isolated environment Local Web prod DB DATABASE_URL=postgres://127.0.0.1:30002/main symfony tunnel:open 2 some-bug some-bug Web symfony server:start 3 some-bug some-bug Web DB symfony env:create Duplicate infra/data Create a local Git branch 1 symfony env:sync
  36. https://some-bug-xtf33gy-ombjum625h7iw.eu.s5y.io/ Step 4: Fix the issue # Fix the code

    # Update the DB schema # Change/Add some services $ git commit ... # Deploy on the remote env $ symfony deploy # Check that everything is fine $ symfony open:remote # If the fix takes some time # Sync back the data from prod $ symfony env:sync ENV=prod DEBUG=false
  37. https://demo.com/ === https://some-bug-xtf33gy-ombjum625h7iw.eu.s5y.io/ Step 5: Deploy with confidence # Merge

    everything back (code + infra) to production $ git checkout master $ git merge some-bug # Deploy production # Fast -> same container images $ symfony deploy ENV=prod DEBUG=false
  38. Bonus: Works in a terminal as well $ symfony tunnel:open

    $ symfony php -r 'echo $_SERVER["DATABASE_URL"];' postgres://main:[email protected]:30002/main?sslmode=disable&charset=utf8&serverVersion=10 # Env vars are useful with bin/console as well $ symfony console ... # Works for "some" other commands as well (connects to the SymfonyCloud DB) $ symfony run psql SymfonyCloud Environment variables are set
  39. My ideal setup! Local Web Server and local files Remote

    services Works well on the major platforms Fast and convenient