Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crashes when run against installed nextcloud. #549

Open
blmhemu opened this issue Feb 4, 2024 · 10 comments
Open

Crashes when run against installed nextcloud. #549

blmhemu opened this issue Feb 4, 2024 · 10 comments
Labels
bug Something isn't working

Comments

@blmhemu
Copy link
Contributor

blmhemu commented Feb 4, 2024

What happened?

Disclaimer: I have zero prior experience in php - so if you find this bug report irrelevant, lmk.

I tried to hack together the nextcloud dockerfile to make it work with frankenphp - The original code can be found at https://github.com/nextcloud/docker/tree/master/28/apache

I have basically change the build container to frakenphp and the entry point to frankenphp run --config /etc/caddy/Caddyfile

The TLDR can be - how to run nextcloud under frankenphp ?

Dockerfile
# DO NOT EDIT: created by update.sh from Dockerfile-alpine.template
FROM dunglas/frankenphp:1.1-php8.2-alpine
# FROM php:8.2-fpm-alpine3.19

# entrypoint.sh and cron.sh dependencies
RUN set -ex; \
  \
  apk add --no-cache \
  imagemagick \
  rsync \
  ; \
  \
  rm /var/spool/cron/crontabs/root; \
  echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data

# install the PHP extensions we need
# see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html
RUN set -ex; \
  \
  apk add --no-cache --virtual .build-deps \
  $PHPIZE_DEPS \
  autoconf \
  freetype-dev \
  gmp-dev \
  icu-dev \
  imagemagick-dev \
  libevent-dev \
  libjpeg-turbo-dev \
  libmcrypt-dev \
  libmemcached-dev \
  libpng-dev \
  libwebp-dev \
  libxml2-dev \
  libzip-dev \
  openldap-dev \
  pcre-dev \
  postgresql-dev \
  ; \
  \
  docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \
  docker-php-ext-configure ldap; \
  docker-php-ext-install -j "$(nproc)" \
  bcmath \
  exif \
  gd \
  gmp \
  intl \
  ldap \
  opcache \
  pcntl \
  pdo_mysql \
  pdo_pgsql \
  sysvsem \
  zip \
  ; \
  \
  # pecl will claim success even if one install fails, so we need to perform each install separately
  pecl install APCu-5.1.23; \
  pecl install imagick-3.7.0; \
  pecl install memcached-3.2.0; \
  pecl install redis-6.0.2; \
  \
  docker-php-ext-enable \
  apcu \
  imagick \
  memcached \
  redis \
  ; \
  rm -r /tmp/pear; \
  \
  runDeps="$( \
  scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
  | tr ',' '\n' \
  | sort -u \
  | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
  )"; \
  apk add --no-network --virtual .nextcloud-phpext-rundeps $runDeps; \
  apk del --no-network .build-deps

# set recommended PHP.ini settings
# see https://docs.nextcloud.com/server/latest/admin_manual/installation/server_tuning.html#enable-php-opcache
ENV PHP_MEMORY_LIMIT 512M
ENV PHP_UPLOAD_LIMIT 512M
RUN { \
  echo 'opcache.enable=1'; \
  echo 'opcache.interned_strings_buffer=32'; \
  echo 'opcache.max_accelerated_files=10000'; \
  echo 'opcache.memory_consumption=128'; \
  echo 'opcache.save_comments=1'; \
  echo 'opcache.revalidate_freq=60'; \
  echo 'opcache.jit=1255'; \
  echo 'opcache.jit_buffer_size=128M'; \
  } > "${PHP_INI_DIR}/conf.d/opcache-recommended.ini"; \
  \
  echo 'apc.enable_cli=1' >> "${PHP_INI_DIR}/conf.d/docker-php-ext-apcu.ini"; \
  \
  { \
  echo 'memory_limit=${PHP_MEMORY_LIMIT}'; \
  echo 'upload_max_filesize=${PHP_UPLOAD_LIMIT}'; \
  echo 'post_max_size=${PHP_UPLOAD_LIMIT}'; \
  } > "${PHP_INI_DIR}/conf.d/nextcloud.ini"; \
  \
  mkdir /var/www/data; \
  mkdir -p /docker-entrypoint-hooks.d/pre-installation \
  /docker-entrypoint-hooks.d/post-installation \
  /docker-entrypoint-hooks.d/pre-upgrade \
  /docker-entrypoint-hooks.d/post-upgrade \
  /docker-entrypoint-hooks.d/before-starting; \
  chown -R www-data:root /var/www; \
  chmod -R g=u /var/www

VOLUME /var/www/html


ENV NEXTCLOUD_VERSION 28.0.2

RUN set -ex; \
  apk add --no-cache --virtual .fetch-deps \
  bzip2 \
  gnupg \
  ; \
  \
  curl -fsSL -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-28.0.2.tar.bz2"; \
  curl -fsSL -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-28.0.2.tar.bz2.asc"; \
  export GNUPGHOME="$(mktemp -d)"; \
  # gpg key from https://nextcloud.com/nextcloud.asc
  gpg --batch --keyserver keyserver.ubuntu.com  --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \
  gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2; \
  tar -xjf nextcloud.tar.bz2 -C /usr/src/; \
  gpgconf --kill all; \
  rm nextcloud.tar.bz2.asc nextcloud.tar.bz2; \
  rm -rf "$GNUPGHOME" /usr/src/nextcloud/updater; \
  mkdir -p /usr/src/nextcloud/data; \
  mkdir -p /usr/src/nextcloud/custom_apps; \
  chmod +x /usr/src/nextcloud/occ; \
  apk del --no-network .fetch-deps

# RUN setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp
# Caddy requires write access to /data/caddy and /config/caddy
# RUN chown -R www-data:www-data /data/caddy && chown -R www-data:www-data /config/caddy

COPY *.sh upgrade.exclude /
COPY config/* /usr/src/nextcloud/config/

ENTRYPOINT ["/entrypoint.sh"]
# CMD ["php-fpm"]
CMD ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

I also made a small change to entrypoint into run nextcloud installations for frankenphp

entrypoint
#!/bin/sh
set -eu

# version_greater A B returns whether A > B
version_greater() {
	[ "$(printf '%s\n' "$@" | sort -t '.' -n -k1,1 -k2,2 -k3,3 -k4,4 | head -n 1)" != "$1" ]
}

# return true if specified directory is empty
directory_empty() {
	[ -z "$(ls -A "$1/")" ]
}

run_as() {
	if [ "$(id -u)" = 0 ]; then
		su -p "$user" -s /bin/sh -c "$1"
	else
		sh -c "$1"
	fi
}

# Execute all executable files in a given directory in alphanumeric order
run_path() {
	local hook_folder_path="/docker-entrypoint-hooks.d/$1"
	local return_code=0

	if ! [ -d "${hook_folder_path}" ]; then
		echo "=> Skipping the folder \"${hook_folder_path}\", because it doesn't exist"
		return 0
	fi

	echo "=> Searching for scripts (*.sh) to run, located in the folder: ${hook_folder_path}"

	(
		find "${hook_folder_path}" -maxdepth 1 -iname '*.sh' '(' -type f -o -type l ')' -print | sort | while read -r script_file_path; do
			if ! [ -x "${script_file_path}" ]; then
				echo "==> The script \"${script_file_path}\" was skipped, because it didn't have the executable flag"
				continue
			fi

			echo "==> Running the script (cwd: $(pwd)): \"${script_file_path}\""

			run_as "${script_file_path}" || return_code="$?"

			if [ "${return_code}" -ne "0" ]; then
				echo "==> Failed at executing \"${script_file_path}\". Exit code: ${return_code}"
				exit 1
			fi

			echo "==> Finished the script: \"${script_file_path}\""
		done
	)
}

# usage: file_env VAR [DEFAULT]
#    ie: file_env 'XYZ_DB_PASSWORD' 'example'
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
#  "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
file_env() {
	local var="$1"
	local fileVar="${var}_FILE"
	local def="${2:-}"
	local varValue=$(env | grep -E "^${var}=" | sed -E -e "s/^${var}=//")
	local fileVarValue=$(env | grep -E "^${fileVar}=" | sed -E -e "s/^${fileVar}=//")
	if [ -n "${varValue}" ] && [ -n "${fileVarValue}" ]; then
		echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
		exit 1
	fi
	if [ -n "${varValue}" ]; then
		export "$var"="${varValue}"
	elif [ -n "${fileVarValue}" ]; then
		export "$var"="$(cat "${fileVarValue}")"
	elif [ -n "${def}" ]; then
		export "$var"="$def"
	fi
	unset "$fileVar"
}

if expr "$1" : "apache" 1>/dev/null; then
	if [ -n "${APACHE_DISABLE_REWRITE_IP+x}" ]; then
		a2disconf remoteip
	fi
fi

if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "$1" = "frankenphp" ] || [ "${NEXTCLOUD_UPDATE:-0}" -eq 1 ]; then
	uid="$(id -u)"
	gid="$(id -g)"
	if [ "$uid" = '0' ]; then
		case "$1" in
		apache2*)
			user="${APACHE_RUN_USER:-www-data}"
			group="${APACHE_RUN_GROUP:-www-data}"

			# strip off any '#' symbol ('#1000' is valid syntax for Apache)
			user="${user#'#'}"
			group="${group#'#'}"
			;;
		*) # php-fpm
			user='www-data'
			group='www-data'
			;;
		esac
	else
		user="$uid"
		group="$gid"
	fi

	if [ -n "${REDIS_HOST+x}" ]; then

		echo "Configuring Redis as session handler"
		{
			file_env REDIS_HOST_PASSWORD
			echo 'session.save_handler = redis'
			# check if redis host is an unix socket path
			if [ "$(echo "$REDIS_HOST" | cut -c1-1)" = "/" ]; then
				if [ -n "${REDIS_HOST_PASSWORD+x}" ]; then
					echo "session.save_path = \"unix://${REDIS_HOST}?auth=${REDIS_HOST_PASSWORD}\""
				else
					echo "session.save_path = \"unix://${REDIS_HOST}\""
				fi
			# check if redis password has been set
			elif [ -n "${REDIS_HOST_PASSWORD+x}" ]; then
				echo "session.save_path = \"tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}?auth=${REDIS_HOST_PASSWORD}\""
			else
				echo "session.save_path = \"tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}\""
			fi
			echo "redis.session.locking_enabled = 1"
			echo "redis.session.lock_retries = -1"
			# redis.session.lock_wait_time is specified in microseconds.
			# Wait 10ms before retrying the lock rather than the default 2ms.
			echo "redis.session.lock_wait_time = 10000"
		} >/usr/local/etc/php/conf.d/redis-session.ini
	fi

	# If another process is syncing the html folder, wait for
	# it to be done, then escape initalization.
	(
		if ! flock -n 9; then
			# If we couldn't get it immediately, show a message, then wait for real
			echo "Another process is initializing Nextcloud. Waiting..."
			flock 9
		fi

		installed_version="0.0.0.0"
		if [ -f /var/www/html/version.php ]; then
			# shellcheck disable=SC2016
			installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
		fi
		# shellcheck disable=SC2016
		image_version="$(php -r 'require "/usr/src/nextcloud/version.php"; echo implode(".", $OC_Version);')"

		if version_greater "$installed_version" "$image_version"; then
			echo "Can't start Nextcloud because the version of the data ($installed_version) is higher than the docker image version ($image_version) and downgrading is not supported. Are you sure you have pulled the newest image version?"
			exit 1
		fi

		if version_greater "$image_version" "$installed_version"; then
			echo "Initializing nextcloud $image_version ..."
			if [ "$installed_version" != "0.0.0.0" ]; then
				if [ "${image_version%%.*}" -gt "$((${installed_version%%.*} + 1))" ]; then
					echo "Can't start Nextcloud because upgrading from $installed_version to $image_version is not supported."
					echo "It is only possible to upgrade one major version at a time. For example, if you want to upgrade from version 14 to 16, you will have to upgrade from version 14 to 15, then from 15 to 16."
					exit 1
				fi
				echo "Upgrading nextcloud from $installed_version ..."
				run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" >/tmp/list_before
			fi
			if [ "$(id -u)" = 0 ]; then
				rsync_options="-rlDog --chown $user:$group"
			else
				rsync_options="-rlD"
			fi

			rsync $rsync_options --delete --exclude-from=/upgrade.exclude /usr/src/nextcloud/ /var/www/html/
			for dir in config data custom_apps themes; do
				if [ ! -d "/var/www/html/$dir" ] || directory_empty "/var/www/html/$dir"; then
					rsync $rsync_options --include "/$dir/" --exclude '/*' /usr/src/nextcloud/ /var/www/html/
				fi
			done
			rsync $rsync_options --include '/version.php' --exclude '/*' /usr/src/nextcloud/ /var/www/html/

			# Install
			if [ "$installed_version" = "0.0.0.0" ]; then
				echo "New nextcloud instance"

				file_env NEXTCLOUD_ADMIN_PASSWORD
				file_env NEXTCLOUD_ADMIN_USER

				if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then
					# shellcheck disable=SC2016
					install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"'
					if [ -n "${NEXTCLOUD_DATA_DIR+x}" ]; then
						# shellcheck disable=SC2016
						install_options=$install_options' --data-dir "$NEXTCLOUD_DATA_DIR"'
					fi

					file_env MYSQL_DATABASE
					file_env MYSQL_PASSWORD
					file_env MYSQL_USER
					file_env POSTGRES_DB
					file_env POSTGRES_PASSWORD
					file_env POSTGRES_USER

					install=false
					if [ -n "${SQLITE_DATABASE+x}" ]; then
						echo "Installing with SQLite database"
						# shellcheck disable=SC2016
						install_options=$install_options' --database-name "$SQLITE_DATABASE"'
						install=true
					elif [ -n "${MYSQL_DATABASE+x}" ] && [ -n "${MYSQL_USER+x}" ] && [ -n "${MYSQL_PASSWORD+x}" ] && [ -n "${MYSQL_HOST+x}" ]; then
						echo "Installing with MySQL database"
						# shellcheck disable=SC2016
						install_options=$install_options' --database mysql --database-name "$MYSQL_DATABASE" --database-user "$MYSQL_USER" --database-pass "$MYSQL_PASSWORD" --database-host "$MYSQL_HOST"'
						install=true
					elif [ -n "${POSTGRES_DB+x}" ] && [ -n "${POSTGRES_USER+x}" ] && [ -n "${POSTGRES_PASSWORD+x}" ] && [ -n "${POSTGRES_HOST+x}" ]; then
						echo "Installing with PostgreSQL database"
						# shellcheck disable=SC2016
						install_options=$install_options' --database pgsql --database-name "$POSTGRES_DB" --database-user "$POSTGRES_USER" --database-pass "$POSTGRES_PASSWORD" --database-host "$POSTGRES_HOST"'
						install=true
					fi

					if [ "$install" = true ]; then
						run_path pre-installation

						echo "Starting nextcloud installation"
						max_retries=10
						try=0
						until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ]; do
							echo "Retrying install..."
							try=$((try + 1))
							sleep 10s
						done
						if [ "$try" -gt "$max_retries" ]; then
							echo "Installing of nextcloud failed!"
							exit 1
						fi
						if [ -n "${NEXTCLOUD_TRUSTED_DOMAINS+x}" ]; then
							echo "Setting trusted domains…"
							NC_TRUSTED_DOMAIN_IDX=1
							for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS; do
								DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
								run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN"
								NC_TRUSTED_DOMAIN_IDX=$((NC_TRUSTED_DOMAIN_IDX + 1))
							done
						fi

						run_path post-installation
					else
						echo "Please run the web-based installer on first connect!"
					fi
				fi
			# Upgrade
			else
				run_path pre-upgrade

				run_as 'php /var/www/html/occ upgrade'

				run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" >/tmp/list_after
				echo "The following apps have been disabled:"
				diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1
				rm -f /tmp/list_before /tmp/list_after

				run_path post-upgrade
			fi

			echo "Initializing finished"
		fi

		# Update htaccess after init if requested
		if [ -n "${NEXTCLOUD_INIT_HTACCESS+x}" ] && [ "$installed_version" != "0.0.0.0" ]; then
			run_as 'php /var/www/html/occ maintenance:update:htaccess'
		fi
	) 9>/var/www/html/nextcloud-init-sync.lock

	run_path before-starting
fi

exec "$@"
Caddy logs
app-1    | New nextcloud instance
app-1    | Installing with PostgreSQL database
app-1    | => Searching for scripts (*.sh) to run, located in the folder: /docker-entrypoint-hooks.d/pre-installation
app-1    | Starting nextcloud installation
app-1    | Nextcloud was successfully installed
app-1    | => Searching for scripts (*.sh) to run, located in the folder: /docker-entrypoint-hooks.d/post-installation
app-1    | Initializing finished
app-1    | => Searching for scripts (*.sh) to run, located in the folder: /docker-entrypoint-hooks.d/before-starting
app-1    | {"level":"info","ts":1707121293.4429927,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":""}
app-1    | {"level":"info","ts":1707121293.4698567,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
app-1    | {"level":"info","ts":1707121293.4729865,"logger":"http.auto_https","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
app-1    | {"level":"info","ts":1707121293.4733138,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
app-1    | {"level":"info","ts":1707121293.4752572,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00042ca00"}
app-1    | {"level":"info","ts":1707121293.4928567,"msg":"FrankenPHP started 🐘","php_version":"8.2.15"}
app-1    | {"level":"info","ts":1707121293.5175326,"logger":"tls","msg":"cleaning storage unit","storage":"FileStorage:/data/caddy"}
app-1    | {"level":"info","ts":1707121293.5254633,"logger":"tls","msg":"finished cleaning storage units"}
app-1    | {"level":"warn","ts":1707121294.02207,"logger":"pki.ca.local","msg":"installing root certificate (you might be prompted for password)","path":"storage:pki/authorities/local/root.crt"}
app-1    | {"level":"info","ts":1707121294.0234227,"msg":"warning: \"certutil\" is not available, install \"certutil\" with \"apt install libnss3-tools\" or \"yum install nss-tools\" and try again"}
app-1    | {"level":"info","ts":1707121294.0236008,"msg":"define JAVA_HOME environment variable to use the Java trust"}
app-1    | {"level":"info","ts":1707121300.6172276,"msg":"certificate installed properly in linux trusts"}
app-1    | {"level":"info","ts":1707121300.6183708,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
app-1    | {"level":"info","ts":1707121300.6520422,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details."}
app-1    | {"level":"info","ts":1707121300.655253,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
app-1    | {"level":"info","ts":1707121300.6573725,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
app-1    | {"level":"info","ts":1707121300.657596,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["localhost"]}
app-1    | {"level":"info","ts":1707121300.6600044,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
app-1    | {"level":"info","ts":1707121300.6603096,"msg":"serving initial configuration"}
app-1    | {"level":"info","ts":1707121300.665742,"logger":"tls.obtain","msg":"acquiring lock","identifier":"localhost"}
app-1    | {"level":"info","ts":1707121300.684313,"logger":"tls.obtain","msg":"lock acquired","identifier":"localhost"}
app-1    | {"level":"info","ts":1707121300.685793,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"localhost"}
app-1    | {"level":"info","ts":1707121300.7016816,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"localhost"}
app-1    | {"level":"info","ts":1707121300.7032683,"logger":"tls.obtain","msg":"releasing lock","identifier":"localhost"}
app-1    | {"level":"warn","ts":1707121300.709363,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [localhost]: no OCSP server specified in certificate","identifiers":["localhost"]}
app-1 exited with code 0

Now when I try to run the docker image with the below caddyfile

{
  debug
	frankenphp

	order mercure after encode
	order vulcain after reverse_proxy
	order php_server before file_server
	order php before file_server
}

localhost {
	root * /var/www/html/
	encode zstd br gzip

	php_server
}

The container crashes when I visit https://localhost

Build Type

Docker (Alpine)

Worker Mode

No

Operating System

GNU/Linux

CPU Architecture

x86_64

Relevant log output

No response

@blmhemu blmhemu added the bug Something isn't working label Feb 4, 2024
@withinboredom
Copy link
Collaborator

I see an exit code 0, so something cleanly terminated the server. That would be a good starting point, try to figure out why the server is exiting.

@blmhemu
Copy link
Contributor Author

blmhemu commented Feb 7, 2024

Hey ! I suspect it may be due to user change as I see some logs mentioning cannot create directories.

To add more info, when run with the worker mode, it crashes with code 139

The app seems to work fine with php-fpm - likely because of the user and group settings in fpm config.

Worker mode logs
app-1    | {"level":"info","ts":1707285398.4587631,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4600906,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4621444,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.464938,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4678853,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4696634,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4722056,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4762714,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4780812,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4812984,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.484174,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4860249,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.487745,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4927628,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4943702,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4953227,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4966986,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4979026,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.4991028,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5024211,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5029106,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.505871,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5074112,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5090914,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.511721,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5135226,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5152075,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5169046,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5195568,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5241697,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5267816,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5330698,"msg":"restarting","worker":"/var/www/html/index.php"}
app-1    | {"level":"info","ts":1707285398.5395887,"msg":"restarting","worker":"/var/www/html/index.php"}
db-1     | 2024-02-07 05:56:38.550 UTC [440] LOG:  could not receive data from client: Connection reset by peer
app-1 exited with code 139

@withinboredom
Copy link
Collaborator

yes, php-fpm starts as root and then switches users after opening ports. Caddy starts as whatever user starts it and that's it. This means if you want to open a port less than 1024, you'll need to give it permission to do so, as well as give it access to whatever folders it needs access to as that user.

There's a pretty good guide here: https://www.booleanworld.com/host-website-caddy-web-server-linux/ that is still relevant and covers all the details.

@blmhemu
Copy link
Contributor Author

blmhemu commented Feb 9, 2024

Have updated the docs at #565 as I wasn't able to use the existing example.

@blmhemu
Copy link
Contributor Author

blmhemu commented Feb 10, 2024

I have been able to create a container which runs as www-data. Now I see segmentation fault in the frankenphp.

app-1    | {"level":"info","ts":1707555919.3249483,"logger":"tls","msg":"finished cleaning storage units"}
app-1    | Segmentation fault
app-1 exited with code 0

@withinboredom
Copy link
Collaborator

Hmm, I see it uses amphp which uses fibers, which means you might be hitting #46 ...

@withinboredom
Copy link
Collaborator

withinboredom commented Feb 11, 2024

Something I haven't tried, but might be worth trying, is to try putting this in your worker script:

// at the beginning of the request
ob_start();

// handle request

// at the very end of the request
ob_end_flush();

That should prevent any output from being sent to Go inside a fiber 🤞 and prevent the crash. I'm not sure about headers, which we would also want to prevent. It would also prevent any streaming responses from working, so it isn't ideal. At all (and might break many things).

@withinboredom
Copy link
Collaborator

@dunglas it just occurred to me (and possibly not even related to the main issue) that it might be worth asking in internals if there is a way to switch back to the main stack in C, then send the data to Go, then switch the stack back to the target stack and resume execution; instead of sending output directly to Go.

Something like this:

void handleOutputCallback(/*args*/) {
  if(!in_fiber()) {
    go_output(/*args*/);
  }

  original_stack = switch_fiber_stack_main();
  go_output(/*args*/);
  switch_fiber_stack(original_stack);
}

I'm pretty sick today, so I can't do anything complicated like digging into that.

@hugo-akaora
Copy link

Hello, can reproduce using FrankenPHP standalone binary on arm64 (Raspberry Pi 3)

I can successfully install Nextcloud using occ command :

OCC_CMD="./frankenphp php-cli nextcloud/occ"
$OCC_CMD maintenance:install \
    --database='pgsql' --database-name='nextcloud' --database-host='localhost' \
    --database-user='nextcloud' --database-pass='nextcloud' \
    --admin-user='admin' --admin-pass='admin

When, at the first connection using the Web UI, I got a segmentation fault:

root@DietPi:/mnt/dietpi_userdata/iglou# ./frankenphp php-server
2024/05/01 09:53:22.085	WARN	admin	admin endpoint disabled
2024/05/01 09:53:22.085	WARN	http.auto_https	server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server	{"server_name": "php", "http_port": 80}
2024/05/01 09:53:22.085	INFO	tls.cache.maintenance	started background certificate maintenance	{"cache": "0x40004de100"}
2024/05/01 09:53:22.088	INFO	FrankenPHP started 🐘	{"php_version": "8.3.6"}
2024/05/01 09:53:22.090	INFO	http.log	server running	{"name": "php", "protocols": ["h1", "h2", "h3"]}
2024/05/01 09:53:22.090	INFO	Caddy serving PHP app on :80
2024/05/01 09:53:22.147	WARN	tls	storage cleaning happened too recently; skipping for now	{"storage": "FileStorage:/root/.local/share/caddy", "instance": "598d3c03-4a41-4648-bf3f-e649b833ae03", "try_again": "2024/05/02 09:53:22.147", "try_again_in": 86399.999997343}
2024/05/01 09:53:22.148	INFO	tls	finished cleaning storage units
Segmentation fault

I could try to reproduce it on x86_64, if it is useful?
Thanks

@dunglas
Copy link
Owner

dunglas commented May 1, 2024

What would be the most useful is a stack trace.

You can gather one by following these instructions: https://frankenphp.dev/docs/contributing/#debugging-segmentation-faults-with-static-builds

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants