-
-
Save nginx-gists/bdc7da70b124c4f3e472970c7826cccc to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash | |
if [ "$EUID" -ne 0 ];then | |
>&2 echo "This script requires root level access to run" | |
exit 1 | |
fi | |
if [ -z "${WORDPRESS_DB_PASSWORD}" ]; then | |
>&2 echo "WORDPRESS_DB_PASSWORD must be set" | |
>&2 echo "Here is a random one that you can paste:" | |
>&2 echo "export WORDPRESS_DB_PASSWORD=\"$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)\"" | |
exit 1 | |
fi | |
if [ -z "${WORDPRESS_ADMIN_USER}" ]; then | |
>&2 echo "WORDPRESS_ADMIN_USER must be set" | |
>&2 echo "Here is a sensible default that you can paste:" | |
>&2 echo "export WORDPRESS_ADMIN_USER=\"moderator\"" | |
exit 1 | |
fi | |
if [ -z "${WORDPRESS_ADMIN_PASSWORD}" ]; then | |
>&2 echo "WORDPRESS_ADMIN_PASSWORD must be set" | |
>&2 echo "Here is a random one that you can paste:" | |
>&2 echo "export WORDPRESS_ADMIN_PASSWORD=\"$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)\"" | |
exit 1 | |
fi | |
if [ -z "${WORDPRESS_ADMIN_EMAIL}" ]; then | |
>&2 echo "WORDPRESS_ADMIN_EMAIL must be set" | |
exit 1 | |
fi | |
if [ -z "${WORDPRESS_URL}" ]; then | |
>&2 echo "WORDPRESS_URL must be set" | |
exit 1 | |
fi | |
if [ -z "${WORDPRESS_SITE_TITLE}" ]; then | |
>&2 echo "WORDPRESS_SITE_TITLE must be set" | |
exit 1 | |
fi | |
# Best practice settings for running bash scripts: | |
# Exit the script when an error is encountered | |
set -o errexit | |
# Exit the script when a pipe operation fails | |
set -o pipefail | |
# Exit the script when there are undeclared variables | |
set -o nounset | |
# Uncomment this to see a log to the screen of each command run in the script | |
# set -o xtrace | |
export DEBIAN_FRONTEND="noninteractive" | |
export WORDPRESS_CLI_VERSION="2.4.0" | |
export WORDPRESS_CLI_MD5="dedd5a662b80cda66e9e25d44c23b25c" | |
export UPLOAD_MAX_FILESIZE="16M" | |
export TLS_HOSTNAME="$(echo ${WORDPRESS_URL} | cut -d'/' -f3)" | |
export NGINX_CONF_DIR="/etc/nginx" | |
export CERT_DIR="/etc/letsencrypt/live/${TLS_HOSTNAME}" | |
# Change the hostname to be the same as the WordPress hostname | |
if [ ! "$(hostname)" == "${TLS_HOSTNAME}" ]; then | |
echo "▶ Changing hostname to ${TLS_HOSTNAME}" | |
hostnamectl set-hostname "${TLS_HOSTNAME}" | |
fi | |
# Add the hostname to /etc/hosts | |
if [ "$(grep -m1 "${TLS_HOSTNAME}" /etc/hosts)" = "" ]; then | |
echo "▶ Adding hostname ${TLS_HOSTNAME} to /etc/hosts so that WordPress can ping itself" | |
printf "::1 %s\n127.0.0.1 %s\n" "${TLS_HOSTNAME}" "${TLS_HOSTNAME}" >> /etc/hosts | |
fi | |
# Make sure tools needed for install are present | |
echo "▶ Installing prerequisite tools" | |
apt-get -qq update | |
apt-get -qq install -y \ | |
bc \ | |
ca-certificates \ | |
coreutils \ | |
curl \ | |
gnupg2 \ | |
lsb-release | |
# Install the NGINX Unit repository | |
if [ ! -f /etc/apt/sources.list.d/unit.list ]; then | |
echo "▶ Installing NGINX Unit repository" | |
curl -fsSL https://nginx.org/keys/nginx_signing.key | apt-key add - | |
echo "deb https://packages.nginx.org/unit/ubuntu/ $(lsb_release -cs) unit" > /etc/apt/sources.list.d/unit.list | |
fi | |
# Install the NGINX repository | |
if [ ! -f /etc/apt/sources.list.d/nginx.list ]; then | |
echo "▶ Installing NGINX repository" | |
curl -fsSL https://nginx.org/keys/nginx_signing.key | apt-key add - | |
echo "deb https://nginx.org/packages/mainline/ubuntu $(lsb_release -cs) nginx" > /etc/apt/sources.list.d/nginx.list | |
fi | |
echo "▶ Updating repository metadata" | |
apt-get -qq update | |
# WordPress module recommendation: https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions | |
# Ubuntu bundles the following PHP extensions with its package distribution: | |
# date filter hash libxml openssl pcntl pcre Reflection session sodium SPL | |
# standard zlib | |
# The php-common package contains the following extensions: exif | |
# Install PHP with dependencies and NGINX Unit | |
echo "▶ Installing PHP, NGINX Unit, NGINX, Certbot, and MariaDB" | |
apt-get -qq install -y --no-install-recommends \ | |
certbot \ | |
python3-certbot-nginx \ | |
php-cli \ | |
php-common \ | |
php-bcmath \ | |
php-curl \ | |
php-gd \ | |
php-imagick \ | |
php-mbstring \ | |
php-mysql \ | |
php-opcache \ | |
php-xml \ | |
php-zip \ | |
ghostscript \ | |
nginx \ | |
unit \ | |
unit-php \ | |
mariadb-server | |
# Find the major and minor PHP version so that we can write to its conf.d directory | |
PHP_MAJOR_MINOR_VERSION="$(php -v | head -n1 | cut -d' ' -f2 | cut -d'.' -f1,2)" | |
if [ ! -f "/etc/php/${PHP_MAJOR_MINOR_VERSION}/embed/conf.d/30-wordpress-overrides.ini" ]; then | |
echo "▶ Configuring PHP for use with NGINX Unit and WordPress" | |
# Add PHP configuration overrides | |
cat > "/etc/php/${PHP_MAJOR_MINOR_VERSION}/embed/conf.d/30-wordpress-overrides.ini" << EOM | |
; Set a larger maximum upload size so that WordPress can handle | |
; bigger media files. | |
upload_max_filesize=${UPLOAD_MAX_FILESIZE} | |
post_max_size=${UPLOAD_MAX_FILESIZE} | |
; Write error log to STDERR so that error messages show up in the NGINX Unit log | |
error_log=/dev/stderr | |
EOM | |
fi | |
# Restart NGINX Unit because we have reconfigured PHP | |
echo "▶ Restarting NGINX Unit" | |
service unit restart | |
# Set up the WordPress database | |
echo "▶ Configuring MariaDB for WordPress" | |
mysqladmin create wordpress || echo "Ignoring above error because database may already exist" | |
mysql -e "GRANT ALL PRIVILEGES ON wordpress.* TO \"wordpress\"@\"localhost\" IDENTIFIED BY \"$WORDPRESS_DB_PASSWORD\"; FLUSH PRIVILEGES;" | |
if [ ! -f /usr/local/bin/wp ]; then | |
# Install the WordPress CLI | |
echo "▶ Installing the WordPress CLI tool" | |
curl --retry 6 -Ls "https://github.com/wp-cli/wp-cli/releases/download/v${WORDPRESS_CLI_VERSION}/wp-cli-${WORDPRESS_CLI_VERSION}.phar" > /usr/local/bin/wp | |
echo "$WORDPRESS_CLI_MD5 /usr/local/bin/wp" | md5sum -c - | |
chmod +x /usr/local/bin/wp | |
fi | |
if [ ! -d /var/www/wordpress ]; then | |
# Create WordPress directories | |
mkdir -p /var/www/wordpress | |
chown -R www-data:www-data /var/www | |
# Download WordPress using the WordPress CLI | |
echo "▶ Installing WordPress" | |
su -s /bin/sh -c 'wp --path=/var/www/wordpress core download' www-data | |
WP_CONFIG_CREATE_CMD="wp --path=/var/www/wordpress config create --extra-php --dbname=wordpress --dbuser=wordpress --dbhost=\"localhost:/var/run/mysqld/mysqld.sock\" --dbpass=\"${WORDPRESS_DB_PASSWORD}\"" | |
# This snippet is injected into the wp-config.php file when it is created; | |
# it informs WordPress that we are behind a reverse proxy and as such | |
# allows it to generate links using HTTPS | |
cat > /tmp/wp_forwarded_for.php << 'EOM' | |
/* Turn HTTPS 'on' if HTTP_X_FORWARDED_PROTO matches 'https' */ | |
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) { | |
$_SERVER['HTTPS'] = 'on'; | |
} | |
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { | |
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST']; | |
} | |
EOM | |
# Create WordPress configuration | |
su -s /bin/sh -p -c "cat /tmp/wp_forwarded_for.php | ${WP_CONFIG_CREATE_CMD}" www-data | |
rm /tmp/wp_forwarded_for.php | |
su -s /bin/sh -p -c "wp --path=/var/www/wordpress config set 'FORCE_SSL_ADMIN' 'true'" www-data | |
# Install WordPress | |
WP_SITE_INSTALL_CMD="wp --path=/var/www/wordpress core install --url=\"${WORDPRESS_URL}\" --title=\"${WORDPRESS_SITE_TITLE}\" --admin_user=\"${WORDPRESS_ADMIN_USER}\" --admin_password=\"${WORDPRESS_ADMIN_PASSWORD}\" --admin_email=\"${WORDPRESS_ADMIN_EMAIL}\" --skip-email" | |
su -s /bin/sh -p -c "${WP_SITE_INSTALL_CMD}" www-data | |
# Set permalink structure to a sensible default that isn't in the UI | |
su -s /bin/sh -p -c "wp --path=/var/www/wordpress option update permalink_structure '/%year%/%monthnum%/%postname%/'" www-data | |
# Remove sample file because it is cruft and could be a security problem | |
rm /var/www/wordpress/wp-config-sample.php | |
# Ensure that WordPress permissions are correct | |
find /var/www/wordpress -type d -exec chmod g+s {} \; | |
chmod g+w /var/www/wordpress/wp-content | |
chmod -R g+w /var/www/wordpress/wp-content/themes | |
chmod -R g+w /var/www/wordpress/wp-content/plugins | |
fi | |
if [ "${container:-unknown}" != "lxc" ] && [ "$(grep -m1 -a container=lxc /proc/1/environ | tr -d '\0')" == "" ]; then | |
NAMESPACES='"namespaces": { | |
"cgroup": true, | |
"credential": true, | |
"mount": true, | |
"network": false, | |
"pid": true, | |
"uname": true | |
}' | |
else | |
NAMESPACES='"namespaces": {}' | |
fi | |
PHP_MEM_LIMIT="$(grep 'memory_limit' /etc/php/${PHP_MAJOR_MINOR_VERSION}/embed/php.ini | tr -d ' ' | cut -f2 -d= | numfmt --from=iec)" | |
AVAIL_MEM="$(grep MemAvailable /proc/meminfo | tr -d ' kB' | cut -f2 -d: | numfmt --from-unit=K)" | |
MAX_PHP_PROCESSES="$(echo "${AVAIL_MEM}/${PHP_MEM_LIMIT}+5" | bc)" | |
echo "▶ Calculated the maximum number of PHP processes as ${MAX_PHP_PROCESSES}. You may want to tune this value due to variations in your configuration. It is not unusual to see values between 10-100 in production configurations." | |
echo "▶ Configuring NGINX Unit to use PHP and WordPress" | |
cat > /tmp/wordpress.json << EOM | |
{ | |
"settings": { | |
"http": { | |
"header_read_timeout": 30, | |
"body_read_timeout": 30, | |
"send_timeout": 30, | |
"idle_timeout": 180, | |
"max_body_size": $(numfmt --from=iec ${UPLOAD_MAX_FILESIZE}) | |
} | |
}, | |
"listeners": { | |
"127.0.0.1:8080": { | |
"pass": "routes/wordpress" | |
} | |
}, | |
"routes": { | |
"wordpress": [ | |
{ | |
"match": { | |
"uri": [ | |
"*.php", | |
"*.php/*", | |
"/wp-admin/" | |
] | |
}, | |
"action": { | |
"pass": "applications/wordpress/direct" | |
} | |
}, | |
{ | |
"action": { | |
"share": "/var/www/wordpress", | |
"fallback": { | |
"pass": "applications/wordpress/index" | |
} | |
} | |
} | |
] | |
}, | |
"applications": { | |
"wordpress": { | |
"type": "php", | |
"user": "www-data", | |
"group": "www-data", | |
"processes": { | |
"max": ${MAX_PHP_PROCESSES}, | |
"spare": 1 | |
}, | |
"isolation": { | |
${NAMESPACES} | |
}, | |
"targets": { | |
"direct": { | |
"root": "/var/www/wordpress/" | |
}, | |
"index": { | |
"root": "/var/www/wordpress/", | |
"script": "index.php" | |
} | |
} | |
} | |
} | |
} | |
EOM | |
curl -X PUT --data-binary @/tmp/wordpress.json --unix-socket /run/control.unit.sock http://localhost/config | |
# Make directory for NGINX cache | |
mkdir -p /var/cache/nginx/proxy | |
echo "▶ Configuring NGINX" | |
cat > ${NGINX_CONF_DIR}/nginx.conf << EOM | |
user nginx; | |
worker_processes auto; | |
error_log /var/log/nginx/error.log warn; | |
pid /var/run/nginx.pid; | |
events { | |
worker_connections 1024; | |
} | |
http { | |
include ${NGINX_CONF_DIR}/mime.types; | |
default_type application/octet-stream; | |
log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" ' | |
'\$status \$body_bytes_sent "\$http_referer" ' | |
'"\$http_user_agent" "\$http_x_forwarded_for"'; | |
access_log /var/log/nginx/access.log main; | |
sendfile on; | |
client_max_body_size ${UPLOAD_MAX_FILESIZE}; | |
keepalive_timeout 65; | |
# gzip settings | |
include ${NGINX_CONF_DIR}/gzip_compression.conf; | |
# Cache settings | |
proxy_cache_path /var/cache/nginx/proxy | |
levels=1:2 | |
keys_zone=wp_cache:10m | |
max_size=10g | |
inactive=60m | |
use_temp_path=off; | |
include ${NGINX_CONF_DIR}/conf.d/*.conf; | |
} | |
EOM | |
cat > ${NGINX_CONF_DIR}/gzip_compression.conf << 'EOM' | |
# Credit: https://github.com/h5bp/server-configs-nginx/ | |
# ---------------------------------------------------------------------- | |
# | Compression | | |
# ---------------------------------------------------------------------- | |
# https://nginx.org/en/docs/http/ngx_http_gzip_module.html | |
# Enable gzip compression. | |
# Default: off | |
gzip on; | |
# Compression level (1-9). | |
# 5 is a perfect compromise between size and CPU usage, offering about 75% | |
# reduction for most ASCII files (almost identical to level 9). | |
# Default: 1 | |
gzip_comp_level 6; | |
# Don't compress anything that's already small and unlikely to shrink much if at | |
# all (the default is 20 bytes, which is bad as that usually leads to larger | |
# files after gzipping). | |
# Default: 20 | |
gzip_min_length 256; | |
# Compress data even for clients that are connecting to us via proxies, | |
# identified by the "Via" header (required for CloudFront). | |
# Default: off | |
gzip_proxied any; | |
# Tell proxies to cache both the gzipped and regular version of a resource | |
# whenever the client's Accept-Encoding capabilities header varies; | |
# Avoids the issue where a non-gzip capable client (which is extremely rare | |
# today) would display gibberish if their proxy gave them the gzipped version. | |
# Default: off | |
gzip_vary on; | |
# Compress all output labeled with one of the following MIME-types. | |
# `text/html` is always compressed by gzip module. | |
# Default: text/html | |
gzip_types | |
application/atom+xml | |
application/geo+json | |
application/javascript | |
application/x-javascript | |
application/json | |
application/ld+json | |
application/manifest+json | |
application/rdf+xml | |
application/rss+xml | |
application/vnd.ms-fontobject | |
application/wasm | |
application/x-web-app-manifest+json | |
application/xhtml+xml | |
application/xml | |
font/eot | |
font/otf | |
font/ttf | |
image/bmp | |
image/svg+xml | |
text/cache-manifest | |
text/calendar | |
text/css | |
text/javascript | |
text/markdown | |
text/plain | |
text/xml | |
text/vcard | |
text/vnd.rim.location.xloc | |
text/vtt | |
text/x-component | |
text/x-cross-domain-policy; | |
EOM | |
cat > ${NGINX_CONF_DIR}/conf.d/default.conf << EOM | |
upstream unit_php_upstream { | |
server 127.0.0.1:8080; | |
keepalive 32; | |
} | |
server { | |
listen 80; | |
listen [::]:80; | |
# ACME-challenge used by Certbot for Let's Encrypt | |
location ^~ /.well-known/acme-challenge/ { | |
root /var/www/certbot; | |
} | |
location / { | |
return 301 https://${TLS_HOSTNAME}\$request_uri; | |
} | |
} | |
server { | |
listen 443 ssl http2; | |
listen [::]:443 ssl http2; | |
server_name ${TLS_HOSTNAME}; | |
root /var/www/wordpress/; | |
# Let's Encrypt configuration | |
ssl_certificate ${CERT_DIR}/fullchain.pem; | |
ssl_certificate_key ${CERT_DIR}/privkey.pem; | |
ssl_trusted_certificate ${CERT_DIR}/chain.pem; | |
include ${NGINX_CONF_DIR}/options-ssl-nginx.conf; | |
ssl_dhparam ${NGINX_CONF_DIR}/ssl-dhparams.pem; | |
# OCSP stapling | |
ssl_stapling on; | |
ssl_stapling_verify on; | |
# Proxy caching | |
proxy_cache wp_cache; | |
proxy_cache_valid 200 302 1h; | |
proxy_cache_valid 404 1m; | |
proxy_cache_revalidate on; | |
proxy_cache_background_update on; | |
proxy_cache_lock on; | |
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; | |
location = /favicon.ico { | |
log_not_found off; | |
access_log off; | |
} | |
location = /robots.txt { | |
allow all; | |
log_not_found off; | |
access_log off; | |
} | |
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, | |
# .DS_Store (Mac) | |
# Keep logging the requests to parse later (or to pass to firewall utilities | |
# such as fail2ban) | |
location ~ /\. { | |
deny all; | |
} | |
# Deny access to any files with a .php extension in the uploads directory; | |
# works in subdirectory installs and also in multi-site network. | |
# Keep logging the requests to parse later (or to pass to firewall utilities | |
# such as fail2ban). | |
location ~* /(?:uploads|files)/.*\.php\$ { | |
deny all; | |
} | |
# WordPress: deny access to wp-content, wp-includes PHP files | |
location ~* ^/(?:wp-content|wp-includes)/.*\.php\$ { | |
deny all; | |
} | |
# Deny public access to wp-config.php | |
location ~* wp-config.php { | |
deny all; | |
} | |
# Do not log access for static assets, media | |
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ { | |
access_log off; | |
} | |
location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ { | |
add_header Access-Control-Allow-Origin "*"; | |
access_log off; | |
} | |
location / { | |
try_files \$uri @index_php; | |
} | |
location @index_php { | |
proxy_socket_keepalive on; | |
proxy_http_version 1.1; | |
proxy_set_header Connection ""; | |
proxy_set_header X-Real-IP \$remote_addr; | |
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; | |
proxy_set_header X-Forwarded-Proto \$scheme; | |
proxy_set_header Host \$host; | |
proxy_pass http://unit_php_upstream; | |
} | |
location ~* \.php\$ { | |
proxy_socket_keepalive on; | |
proxy_http_version 1.1; | |
proxy_set_header Connection ""; | |
proxy_set_header X-Real-IP \$remote_addr; | |
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; | |
proxy_set_header X-Forwarded-Proto \$scheme; | |
proxy_set_header Host \$host; | |
try_files \$uri =404; | |
proxy_pass http://unit_php_upstream; | |
} | |
} | |
EOM | |
echo "▶ Stopping NGINX in order to set up Let's Encrypt" | |
service nginx stop | |
mkdir -p /var/www/certbot | |
chown www-data:www-data /var/www/certbot | |
chmod g+s /var/www/certbot | |
if [ ! -f ${NGINX_CONF_DIR}/options-ssl-nginx.conf ]; then | |
echo "▶ Downloading recommended TLS parameters" | |
curl --retry 6 -Ls -z "Tue, 14 Apr 2020 16:36:07 GMT" \ | |
-o "${NGINX_CONF_DIR}/options-ssl-nginx.conf" \ | |
"https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf" \ | |
|| echo "Couldn't download latest options-ssl-nginx.conf" | |
fi | |
if [ ! -f ${NGINX_CONF_DIR}/ssl-dhparams.pem ]; then | |
echo "▶ Downloading recommended TLS DH parameters" | |
curl --retry 6 -Ls -z "Tue, 14 Apr 2020 16:49:18 GMT" \ | |
-o "${NGINX_CONF_DIR}/ssl-dhparams.pem" \ | |
"https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem" \ | |
|| echo "Couldn't download latest ssl-dhparams.pem" | |
fi | |
# If tls_certs_init.sh hasn't been run before, remove the self-signed certs | |
if [ ! -d "/etc/letsencrypt/accounts" ]; then | |
echo "▶ Removing self-signed certificates" | |
rm -rf "${CERT_DIR}" | |
fi | |
if [ "" = "${LETS_ENCRYPT_STAGING:-}" ] || [ "0" = "${LETS_ENCRYPT_STAGING}" ]; then | |
CERTBOT_STAGING_FLAG="" | |
else | |
CERTBOT_STAGING_FLAG="--staging" | |
fi | |
if [ ! -f "${CERT_DIR}/fullchain.pem" ]; then | |
echo "▶ Generating certificates with Let's Encrypt" | |
certbot certonly --standalone \ | |
-m "${WORDPRESS_ADMIN_EMAIL}" \ | |
${CERTBOT_STAGING_FLAG} \ | |
--agree-tos --force-renewal --non-interactive \ | |
-d "${TLS_HOSTNAME}" | |
fi | |
echo "▶ Starting NGINX to use new configuration and enabling NGINX Unit service" | |
service nginx start | |
systemctl enable unit.service | |
# Periodic Let's Encrypt cert renewal | |
if [ ! -f "/etc/systemd/system/certbot-renewal.timer" ]; then | |
echo "▶ Adding systemd Certbot renewal service timer" | |
cat > /etc/systemd/system/certbot-renewal.timer << EOM | |
[Unit] | |
Description=Timer for Certbot Renewal | |
[Timer] | |
OnBootSec=300 | |
OnUnitActiveSec=1w | |
[Install] | |
WantedBy=multi-user.target | |
EOM | |
fi | |
echo "▶ Enabling Let's Encrypt auto-renewal" | |
systemctl start certbot-renewal.timer | |
systemctl enable certbot-renewal.timer |
I modified this code to work with Debian 12
# Install the NGINX Unit repository
if [ ! -f /etc/apt/sources.list.d/unit.list ]; then
echo "? Installing NGINX Unit repository"
curl --output /usr/share/keyrings/nginx-keyring.gpg https://unit.nginx.org/keys/nginx-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/nginx-keyring.gpg] https://packages.nginx.org/unit/debian/ bookworm unit \
deb-src [signed-by=/usr/share/keyrings/nginx-keyring.gpg] https://packages.nginx.org/unit/debian/ bookworm unit" > /etc/apt/sources.list.d/unit.list
fi
# Install the NGINX repository
if [ ! -f /etc/apt/sources.list.d/nginx.list ]; then
echo "? Installing NGINX repository"
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/debian `lsb_release -cs` nginx" \
| tee /etc/apt/sources.list.d/nginx.list
fi
everything seems to install fine except for the final step Enabling Let's Encrypt auto-renewal
certbot-renewal.timer: Refusing to start, unit certbot-renewal.service to trigger not loaded.
Failed to start certbot-renewal.timer - Timer for Certbot Renewal.
░░ Subject: A start job for unit certbot-renewal.timer has failed
░░ Defined-By: systemd
░░ Support: https://www.debian.org/support
░░
░░ A start job for unit certbot-renewal.timer has finished with a failure.
░░
░░ The job identifier is 618 and the job result is failed.
Also, my domain that I used in WORDPRESS_URL triggers a 502 Bad Gateway status
should I be doing anything in nginx to get this fixed?
error log
2024/05/29 07:56:42 [error] 548#548: *13 connect() failed (111: Connection refused) while connecting to upstream, client: 192.87.274.38, server: something.org, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "something.org"
port 8080 is not open anywhere, should that port be listening?
lsof -nP -iTCP -sTCP:LISTEN
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 582 root 3u IPv4 2461 0t0 TCP *:22 (LISTEN)
sshd 582 root 4u IPv6 2472 0t0 TCP *:22 (LISTEN)
mariadbd 583 mysql 22u IPv4 2486 0t0 TCP 127.0.0.1:3306 (LISTEN)
nginx 815 root 6u IPv4 18377 0t0 TCP *:80 (LISTEN)
nginx 815 root 7u IPv6 18378 0t0 TCP *:80 (LISTEN)
nginx 815 root 8u IPv4 18379 0t0 TCP *:443 (LISTEN)
nginx 815 root 9u IPv6 18380 0t0 TCP *:443 (LISTEN)
nginx 816 nginx 6u IPv4 18377 0t0 TCP *:80 (LISTEN)
nginx 816 nginx 7u IPv6 18378 0t0 TCP *:80 (LISTEN)
nginx 816 nginx 8u IPv4 18379 0t0 TCP *:443 (LISTEN)
nginx 816 nginx 9u IPv6 18380 0t0 TCP *:443 (LISTEN)
nginx 817 nginx 6u IPv4 18377 0t0 TCP *:80 (LISTEN)
nginx 817 nginx 7u IPv6 18378 0t0 TCP *:80 (LISTEN)
nginx 817 nginx 8u IPv4 18379 0t0 TCP *:443 (LISTEN)
nginx 817 nginx 9u IPv6 18380 0t0 TCP *:443 (LISTEN)
nginx 818 nginx 6u IPv4 18377 0t0 TCP *:80 (LISTEN)
nginx 818 nginx 7u IPv6 18378 0t0 TCP *:80 (LISTEN)
nginx 818 nginx 8u IPv4 18379 0t0 TCP *:443 (LISTEN)
nginx 818 nginx 9u IPv6 18380 0t0 TCP *:443 (LISTEN)
nginx 819 nginx 6u IPv4 18377 0t0 TCP *:80 (LISTEN)
nginx 819 nginx 7u IPv6 18378 0t0 TCP *:80 (LISTEN)
nginx 819 nginx 8u IPv4 18379 0t0 TCP *:443 (LISTEN)
nginx 819 nginx 9u IPv6 18380 0t0 TCP *:443 (LISTEN)
nginx 820 nginx 6u IPv4 18377 0t0 TCP *:80 (LISTEN)
nginx 820 nginx 7u IPv6 18378 0t0 TCP *:80 (LISTEN)
nginx 820 nginx 8u IPv4 18379 0t0 TCP *:443 (LISTEN)
nginx 820 nginx 9u IPv6 18380 0t0 TCP *:443 (LISTEN)
nginx 821 nginx 6u IPv4 18377 0t0 TCP *:80 (LISTEN)
nginx 821 nginx 7u IPv6 18378 0t0 TCP *:80 (LISTEN)
nginx 821 nginx 8u IPv4 18379 0t0 TCP *:443 (LISTEN)
nginx 821 nginx 9u IPv6 18380 0t0 TCP *:443 (LISTEN)
unitd 1064 unit 14u IPv4 22156 0t0 TCP *:8300 (LISTEN)
port 8080 is not open anywhere, should that port be listening?
Yes. If you are running Unit having following conf:
...
"listeners": {
"127.0.0.1:8080": {
"pass": "routes/wordpress"
}
}
...
then port 8080 should be listening:
% lsof -nP -iTCP -sTCP:LISTEN
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
unitd 257625 xim 31u IPv4 959979 0t0 TCP *:8080 (LISTEN)
I had to run the unit configurations again (curl -X PUT --data-binary @wordpress.json --unix-socket /var/run/control.unit.sock http://localhost/config)
now I'm getting a new error ERR_INVALID_REDIRECT
curl -I https://something.org/
HTTP/2 301
server: nginx/1.26.0
date: Wed, 29 May 2024 17:33:58 GMT
content-length: 0
location: //
the /wp-login.php works,
but I was hit with a (413 Content Too Large) error when trying to login,
I removed "max_body_size" from wordpress.json and "client_max_body_size " from nginx.conf
still not able to load the front page, must be some nginx misconfiguration in default.conf
visiting a blog post I am getting the error x-unknown-content-type ns_error_redirect_loop
nginx: [emerg] "upstream" directive is not allowed here in /etc/nginx/conf.d/default.conf:1
@wp-coin the article is 4 years old now. What is the end goal you want to achieve? My thinking is there might be an easier way to get there than debug a script that uses and assumes the state of things as of 2020
For a discussion of these files, see Automating Installation of WordPress with NGINX Unit on Ubuntu