Installing Nginx, PHP and Mysql on Apple M1, MacOS 11 Big Sur


Apple Silicon - M1

This guide will walk you through installing and configuring nginx, PHP and Mysql optimized for MacOS Big Sur on Apple Silicon - M1 Arm processors.

Note: Most of this content originated from this post. Here, I’ve pared it down and fixed the relevant content. Credit goes to the original author: Kevin Dees.

Setup

Before starting you need to install XCode for the command line tools. Open a Terminal and run:

1
xcode-select --install

Next, we need to install Homebrew. Homebrew is a package manager that every MacOS user should have. Installing it won’t hurt anything and you’ll definitely need it for this guide. The newest version of Homebrew has been built natively for the M1 Architecture. When you run this, you should see arm files getting downloaded. This is how you’ll know if a package is compiled natively for M1 / ARM Apple Silicon.

This Homebrew installation method is automated, but if you’re security minded (and should be), you can download the installer script and examine it before running it.

1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

OpenSSL

We’ll need to install OpenSSL to use SSL certificates in nginx. This doesn’t break any existing SSL functionality when installed via Homebrew.

1
brew install openssl

MySQL

Install MySQL.

1
2
3
brew install mysql
brew services start mysql
brew services list

Next, update your my.cnf

1
vi /opt/homebrew/etc/my.cnf

Add this content:

1
2
3
4
5
6
7
8
# Default Homebrew MySQL server config
# Only allow connections from localhost
[mysqld]
bind-address = 127.0.0.1
mysqlx-bind-address = 127.0.0.1

# Add mode only if needed
sql_mode = "ONLY_FULL_GROUP_BY,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"

Now, secure using the password password and then restart.

1
2
mysql_secure_installation
brew services restart mysql

Next, MySQL 8 authentication needs to be updated per user to mysql_native_password. Note that there is no space after the -p. If you add the password on your command line, it will go in your bash history which is a security risk. If you don’t want that, simply use -p and type the password when prompted.

1
2
mysql -u root -ppassword
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';

Postgres SQL DB

Install postgresql

1
2
3
4
brew install postgresql
brew services start postgresql
brew services list
psql postgres

Now, you can check your user list.

1
postgres-# \du

PHP

Don’t use the default homebrew core tap for PHP. Use shivammathur/php.

1
2
3
brew tap shivammathur/php

brew install shivammathur/php/php@7.4

You can verify the new binary is M1 native by running file. The important thing to note is that it is arm64.

1
2
hostname:~ username$ file /opt/homebrew/bin/php
/opt/homebrew/bin/php: Mach-O 64-bit executable `arm64`

Next, set PHP 7.4 as your default php CLI version.

1
2
brew unlink php
brew link --overwrite --force php@7.4

Now, for each version update the php-fpm you will need a unique port. Change the ports of each php-fpm to match its php version number. For example, php@7.4 I use port 9074.

Also, you will want php-fpm to run with your user account and not _www.

1
vi /opt/homebrew/etc/php/7.4/php-fpm.d/www.conf
1
2
3
4
5
6
7
8
9
# default
user = _www
group = _www
listen = 127.0.0.1:9000

# change to
user = <your_username>
group = staff
listen = 127.0.0.1:9074

Optionally, before starting php-fpm, if you want to make edits to a php.ini file now is the time. For example, you might want to increase the upload_max_filesize and post_max_size to 10M.

1
2
3
4
/opt/homebrew/etc/php/7.2/php.ini
/opt/homebrew/etc/php/7.3/php.ini
/opt/homebrew/etc/php/7.4/php.ini
/opt/homebrew/etc/php/8.0/php.ini

Once you are ready, start up php-fpm for each version.

1
sudo brew services start php@7.4

Check that you have processes running and validate your ports are correct.

1
sudo lsof -Pn | grep php-fpm

Nginx

Install nginx.

1
2
brew install nginx
sudo nginx

Now, test the install is working.

1
curl http://localhost:8080

Next let’s change the default settings.

1
vi /opt/homebrew/etc/nginx/nginx.conf

From

1
2
3
listen 8080;
server_name localhost;
index index.html;

To

1
2
3
listen 80;
server_name localhost test.x;
index index.html index.htm index.php;

Next, add a FastCGI gateway to php-fpm on the default server. The latest version of php installed is best. For other servers, you can set the version of PHP to the project requirement.

1
2
3
4
5
6
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9074;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
}

Optionally, add the Universal Coded Character Set for Unicode ( ‘Bəɹʤəɹɑn for example )

1
charset utf-8;

Next, we edit the real index.html file used by nginx. So, replace the index.html with an index.php file. Then, and some php code to make sure everything is working.

mv /opt/homebrew/var/www/index.html /opt/homebrew/var/www/index.php
vi /opt/homebrew/var/www/index.php

1
2
3
<?php
phpinfo();
?>

Now reload nginx:

1
sudo nginx -s reload
1
curl http://localhost

To add more servers you can go to the nginx servers directory, /opt/homebrew/etc/nginx/servers, and add them there as individual files. Here is a basic template.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;

ssl_certificate /opt/homebrew/etc/nginx/ssl/{{host}}.crt;
ssl_certificate_key /opt/homebrew/etc/nginx/ssl/{{host}}.key;
ssl_ciphers HIGH:!aNULL:!MD5;

# listen 80;
server_name {{host}};
root {{root}};

add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";

index index.html index.htm index.php;

charset utf-8;

location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }

access_log off;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

error_page 404 /index.php;

location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9074;
fastcgi_index index.php;
include fastcgi_params;
}

location ~ /\.(?!well-known).* {
deny all;
}
}

To add SSL for your nginx server check out this post. I use these bash functions to make the process faster. To add a server I use the command nginxcreate my.test.x but you might want to modify the files to match your setup.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
alias nginxreload="sudo nginx -s reload"
alias nginxrestart="sudo nginx -s stop && sudo nginx"
alias nginxservers="cd /opt/homebrew/etc/nginx/servers"

function nginxcreate() {
wget https://gist.githubusercontent.com/kevindees/4e3508357ef46676f7635c545e4fd017/raw/f2c2f2716605e4b22a437058e2a7ebf5f8b775b9/nginx-server-template.conf -O /opt/homebrew/etc/nginx/servers/$1.conf

sed -i '' "s:{{host}}:$1:" /opt/homebrew/etc/nginx/servers/$1.conf

if [ "$2" ]; then
sed -i '' "s:{{root}}:$2:" /opt/homebrew/etc/nginx/servers/$1.conf
else
sed -i '' "s:{{root}}:$HOME/Sites/$1:" /opt/homebrew/etc/nginx/servers/$1.conf
fi

nginxaddssl $1

nginxrestart

code /opt/homebrew/etc/nginx/servers/$1.conf
}

function nginxaddssl() {
openssl req \
-x509 -sha256 -nodes -newkey rsa:2048 -days 3650 \
-subj "/CN=$1" \
-reqexts SAN \
-extensions SAN \
-config <(cat /System/Library/OpenSSL/openssl.cnf; printf "[SAN]\nsubjectAltName=DNS:$1") \
-keyout /opt/homebrew/etc/nginx/ssl/$1.key \
-out /opt/homebrew/etc/nginx/ssl/$1.crt

sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /opt/homebrew/etc/nginx/ssl/$1.crt
}

function nginxedit() {
code /opt/homebrew/etc/nginx/servers/$1
}

function nginxlist() {
ll /opt/homebrew/etc/nginx/servers/
}

Redis

Install Redis. This will install Redis Server v6.

1
2
3
brew install redis
brew services start redis
redis-server

Optionally, you can update your default dump.rdb file name in the redis.conf if you want.

1
vi /opt/homebrew/etc/redis.conf

The filename where to dump the DB

1
dbfilename dump.rdb

Resources

Installing Nginx, PHP and Mysql on Apple M1, MacOS 11 Big Sur

https://chrisbergeron.com/2021/03/17/MacOS-11-Big-Sur-Nginx-PHP-and-Mysql/

Author

Chris Bergeron

Posted on

03-17-2021

Updated on

06-26-2021

Licensed under

Comments