Skip to content

Instantly share code, notes, and snippets.

@domtra
Last active January 5, 2023 10:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save domtra/5b266097c2e475d0f18147937fd10bac to your computer and use it in GitHub Desktop.
Save domtra/5b266097c2e475d0f18147937fd10bac to your computer and use it in GitHub Desktop.

Development Environment

MySQL

We are using MySQL 5.7 in our development environment. This is the version that is included in All-Inkl hosting and in many other managed hosting packages.

  1. Install and link brew package
brew install mysql@5.7
brew link --force mysql@5.7
  1. Start MySQL service
brew services start mysql@5.7
  1. Configure MySQL
    • $(brew --prefix)/opt/mysql@5.7/bin/mysql_secure_installation
    • Do NOT install the VALIDATE PASSWORD plugin (just hit enter)
    • New password should be root
    • Remove anonymous users (hit y and enter)
    • Disallow root login remotely (hit y and enter)
    • Remove test database and access to it (hit y and enter)
    • Reload privilege tables now (hit y and enter)

PHP

We are using PHP-FPM. By default we only install those ones supported by core homebrew. These are 7.4 and 8.0 at the moment. 7.3 does not have a bottle for arm64 (M1/Silicon).

Each PHP-FPM service runs on its own port, so we can run them all simultaneously. The port numbers are 9074, 9080, for the respective PHP version.

The process manager is on demand, so that we only use system resources, if request are coming in.

We also install the additional imagemagick module to get better image performance in WordPress.

  1. Install all PHP version and ImageMagick

    brew install php php@7.4 imagemagick
  2. Edit the www.conf files of all PHP versions in $(brew --prefix)/etc/php/X.Y/php-fpm.d/www.conf to include

    listen = 127.0.0.1:90XY
    pm = ondemand
    pm.max_children = 15
  3. Install the imagick module for all 7.4 (prefix can be autodetected). For 8.0 there are compilation errors and an open ticket on GitHub

    $(brew --prefix)/opt/php@7.4/bin/pecl install imagick

Certificates

Instead of sharing real certificates for our local development enironments, we now use a tool called mkcert to trust self-signed certificates system-wide.

  1. Install package

    brew install mkcert nss
  2. Install local certificate authority

    mkcert -install
  3. Generate development certificate

    mkdir ~/certs
    cd ~/certs
    mkcert -key-file local.blee.ch_key.pem -cert-file local.blee.ch_cert.pem local.blee.ch "*.local.blee.ch" "*.dfp-dfa-website.local.blee.ch" "*.ebay-kleinanzeigen.local.blee.ch" "*.mitvergnuegen-website.local.blee.ch" localhost 127.0.0.1 ::1

Apache

Apache runs on port 8080 and 8443. This way we do not need admin rights (sudo) in order to restart the server. We later use port forwarding to route traffic from 80 to 8080 and 443 to 8443.

We also use the MPM Event module for better performance and a couple of other necessary modules.

With the new Macs, we also change the setup a bit so that we can create new virtual hosts easier, and that we set the used PHP version inside of the .htaccess of the projects.

To set everything up, do the following:

  1. Install package

    brew install httpd
  2. Create the file $(brew --prefix)/etc/httpd/extra/h5bp-performance.conf with the following content

    # ######################################################################
    # # WEB PERFORMANCE                                                    #
    # ######################################################################
    
    # ----------------------------------------------------------------------
    # | Compression                                                        |
    # ----------------------------------------------------------------------
    
    <IfModule mod_deflate.c>
    
        # Force compression for mangled `Accept-Encoding` request headers
        # https://developer.yahoo.com/blogs/ydn/pushing-beyond-gzipping-25601.html
    
        <IfModule mod_setenvif.c>
            <IfModule mod_headers.c>
                SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
                RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
            </IfModule>
        </IfModule>
    
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
        # Compress all output labeled with one of the following media types.
        #
        # (!) For Apache versions below version 2.3.7 you don't need to
        # enable `mod_filter` and can remove the `<IfModule mod_filter.c>`
        # and `</IfModule>` lines as `AddOutputFilterByType` is still in
        # the core directives.
        #
        # https://httpd.apache.org/docs/current/mod/mod_filter.html#addoutputfilterbytype
    
        <IfModule mod_filter.c>
            AddOutputFilterByType DEFLATE "application/atom+xml" \
                                          "application/javascript" \
                                          "application/json" \
                                          "application/ld+json" \
                                          "application/manifest+json" \
                                          "application/rdf+xml" \
                                          "application/rss+xml" \
                                          "application/schema+json" \
                                          "application/vnd.geo+json" \
                                          "application/vnd.ms-fontobject" \
                                          "application/x-font-ttf" \
                                          "application/x-javascript" \
                                          "application/x-web-app-manifest+json" \
                                          "application/xhtml+xml" \
                                          "application/xml" \
                                          "font/eot" \
                                          "font/opentype" \
                                          "image/bmp" \
                                          "image/svg+xml" \
                                          "image/vnd.microsoft.icon" \
                                          "image/x-icon" \
                                          "text/cache-manifest" \
                                          "text/css" \
                                          "text/html" \
                                          "text/javascript" \
                                          "text/plain" \
                                          "text/vcard" \
                                          "text/vnd.rim.location.xloc" \
                                          "text/vtt" \
                                          "text/x-component" \
                                          "text/x-cross-domain-policy" \
                                          "text/xml"
    
        </IfModule>
    
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
        # Map the following filename extensions to the specified
        # encoding type in order to make Apache serve the file types
        # with the appropriate `Content-Encoding` response header
        # (do note that this will NOT make Apache compress them!).
        #
        # If these files types would be served without an appropriate
        # `Content-Enable` response header, client applications (e.g.:
        # browsers) wouldn't know that they first need to uncompress
        # the response, and thus, wouldn't be able to understand the
        # content.
        #
        # https://httpd.apache.org/docs/current/mod/mod_mime.html#addencoding
    
        <IfModule mod_mime.c>
            AddEncoding gzip              svgz
        </IfModule>
    
    </IfModule>
  3. Change the following settings in $(brew --prefix)/etc/httpd/httpd.conf

    • Enable (uncomment) the following modules:

      mpm_event_module
      socache_shmcb_module
      deflate_module
      expires_module
      proxy_module
      proxy_fcgi_module
      ssl_module
      http2_module
      vhost_alias_module
      rewrite_module
    • Disable (comment out) the following modules:

      mpm_worker_module
      mpm_prefork_module
    • Add / adjust the following settings, if you do not find a directive (like Protocols), add it to a new line.

      DirectoryIndex index.php index.html
      ServerName localhost
      Protocols h2 http/1.1
    • Enable (uncomment) the include statements for the following config files

      httpd-mpm.conf
      httpd-ssl.conf
    • Add the following includes to the bottom of the file (replace $BREW_PATH with the output of brew --prefix)

      Include $BREW_PATH/etc/httpd/extra/h5bp-performance.conf
    • Add the global certificates (replace $HOME with your home directory)

      SSLProtocol -all +TLSv1.2 +TLSv1.3
      SSLHonorCipherOrder Off
      SSLCipherSuite ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES256:ECDH+AES128:!aNULL:!SHA1:!AESCCM
      SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256
      SSLCertificateFile $HOME/certs/local.blee.ch_cert.pem
      SSLCertificateKeyFile $HOME/certs/local.blee.ch_key.pem
    • Add the following magic virtualhost with default PHP version of 7.4 (replace $BREW_PATH with the output of brew --prefix)

      <Virtualhost *:8443>
          SSLEngine On
          AddHandler proxy:fcgi://127.0.0.1:9074 .php
          VirtualDocumentRoot "$BREW_PATH/var/www/%1"
          ServerName local.blee.ch
          ServerAlias *.local.blee.ch
          UseCanonicalName Off
          <Directory "$BREW_PATH/var/www/*">
              Options Indexes FollowSymLinks MultiViews
              AllowOverride All
              Require all granted
          </Directory>
      </Virtualhost>
    • Add default rewrite settings with a redirect from http to https for all requests

      <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteOptions Inherit
        RewriteCond %{HTTPS} !=on
        RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
      </IfModule>
  4. Remove the entire <Virtualhost ...> directive from $(brew --prefix)/etc/httpd/extra/httpd-ssl.conf.

Port Forwarding

We do portwarding from 80 to 8080 and 443 to 8443 so that apache can be run and restarted without admin right.

For this we have to create a launch daemon and run it as root on boot. You usually do not have to worry about it anymore.

  1. Create the file /Library/LaunchDaemons/local.bleech.httpdfwd.plist with the following content (try sudo touch /Library/LaunchDaemons/local.bleech.httpdfwd.plist before editing with vs-code):

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
     <key>Label</key>
     <string>local.bleech.httpdfwd</string>
     <key>ProgramArguments</key>
     <array>
      <string>sh</string>
      <string>-c</string>
      <string>echo "rdr pass proto tcp from any to any port {80,8080} -> 127.0.0.1 port 8080" | pfctl -a "com.apple/260.HttpFwdFirewall" -Ef - &amp;&amp; echo "rdr pass proto tcp from any to any port {443,8443} -> 127.0.0.1 port 8443" | pfctl -a "com.apple/261.HttpFwdFirewall" -Ef - &amp;&amp; sysctl -w net.inet.ip.forwarding=1</string>
     </array>
     <key>RunAtLoad</key>
     <true/>
     <key>UserName</key>
     <string>root</string>
    </dict>
    </plist>
  2. Load the daemon

    sudo launchctl load -Fw /Library/LaunchDaemons/local.bleech.httpdfwd.plist

dnsmasq

Dnsmasq automatically routes all request to a given domain, in our case local.blee.ch to a specific IP. This way we do not have to add entries for the virtualhosts to /etc/hosts.

  1. Install package

    brew install dnsmasq
  2. Change $(brew --prefix)/etc/dnsmasq.conf to include

    address=/.local.blee.ch/127.0.0.1
    listen-address=127.0.0.1
    port=35353
  3. Create the file (and directory) /etc/resolver/local.blee.ch with the following content

    nameserver 127.0.0.1
    port 35353

brew services

In order to control the tools we just set up, we use brew services. The most relevant subcommands are list|start|stop|restart. Started services will be automatically launched at boot / login.

Here are some helpfull commands (run all of these now, in order to get all services started)

# show all services with status
brew services list
# restart apache, eg. after config change
brew services restart httpd
# restart fpm process for PHP 7.4
brew services restart php@7.4
# restart fpm process for PHP 8.0
brew services restart php@8.0
# restart mysql server
brew services restart mysql@5.7
# restart dnsmasq
brew services restart dnsmasq 

If you do not need specific services or versions of PHP, you can also stop them via brew services stop php@8.0, for example.

Unfortunately the service for PHP-FPM 8.0, sometimes shows an error, although it is running. If you see a red error status when doing brew services list do the following:

  1. Open the .plist file next to the PHP service.
  2. Copy the executed command to the command line (it should be something like /opt/homebrew/opt/php/sbin/php-fpm --nodaemonize).
  3. Run brew services stop php@8.0
  4. Execute the command you copied from the .plist, for example /opt/homebrew/opt/php/sbin/php-fpm --nodaemonize.
  5. If this does not return an error, the service should be running just fine. Hit control + c, and run brew services start php@8.0, again.

Virtualhosts

In order to create a virtualhost, you can create a symlink to the docroot with the project name in $(brew --prefix)/var/www. It will be serverd with the default PHP version. For example

ln -nfs ~/www/bleech-website/wordpress $(brew --prefix)/var/www/bleech-website

As a best practise, always add the used PHP version to the .htaccess of each project. Like

AddHandler proxy:fcgi://127.0.0.1:9080 .php

Tools

Install the following packages

brew install nave composer wp-cli
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment