Slide 1

Slide 1 text

Back to the basics... part 2/n Fabien Potencier @fabpot

Slide 2

Slide 2 text

1) Email reloaded 2) Local Web Server reloaded Fabien Potencier @fabpot

Slide 3

Slide 3 text

The state of local web servers with Symfony php -S Many limitations Docker Might be slow/inconvenient Nginx/Apache Need setup Vagrant Not convenient

Slide 4

Slide 4 text

My ideal setup? Local Web Server and local files Remote services Works well on the major platforms Fast and convenient

Slide 5

Slide 5 text

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) • …

Slide 6

Slide 6 text

A better local web server

Slide 7

Slide 7 text

…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

Slide 8

Slide 8 text

A Symfony local web server # From your project's directory $ symfony server:start # Done! First port available starts at 8000

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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…

Slide 11

Slide 11 text

Managing multiple
 local versions of PHP

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Which PHP versions do you have locally? # Discover what you have $ symfony local:php:list

Slide 14

Slide 14 text

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!

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

# 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?

Slide 20

Slide 20 text

Logs, logs, logs

Slide 21

Slide 21 text

All the logs $ symfony server:start -d $ symfony server:log Tail the logsss

Slide 22

Slide 22 text

All the logs are parsed as semantic JSON logs and "humanized" From the web server From Symfony From PHP

Slide 23

Slide 23 text

Errors are easier to spot

Slide 24

Slide 24 text

# 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

Slide 25

Slide 25 text

Using TLS locally

Slide 26

Slide 26 text

Why? • More similar to production • Detect mixed-content early • Having HTTPS is sometimes a requirement: stripe.js?

Slide 27

Slide 27 text

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/...

Slide 28

Slide 28 text

https://127.0.0.1:8000/ HTTP and HTTPS
 on the same port

Slide 29

Slide 29 text

Local domain names

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Optional, independent from the web server # From anywhere $ symfony proxy:start # Done ...almost! No need to be root

Slide 32

Slide 32 text

+ Nothing to install + No need to mess up with your DNS + Same configuration on all platforms + Does not intercept regular traffic

Slide 33

Slide 33 text

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'; }

Slide 34

Slide 34 text

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/

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

http://127.0.0.1:7080/

Slide 38

Slide 38 text

HTTPS_PROXY=http://localhost:7080 curl -I https://certif.wip/

Slide 39

Slide 39 text

Workers, daemons, ...

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Fully integrated
 with SymfonyCloud and optimized for Symfony projects

Slide 42

Slide 42 text

Use the local web server Connect SymfonyCloud services Browse, it works as you would expect it to!

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

.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!

Slide 48

Slide 48 text

Disabled
 for master/prod by default

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

My ideal setup! Local Web Server and local files Remote services Works well on the major platforms Fast and convenient

Slide 58

Slide 58 text

https://symfony.com/cloud/download Test it today!