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

Xdebug support #235

Open
Anan5a opened this issue Jul 4, 2017 · 14 comments
Open

Xdebug support #235

Anan5a opened this issue Jul 4, 2017 · 14 comments

Comments

@Anan5a
Copy link

Anan5a commented Jul 4, 2017

Why there is no xdebug support on heroku? How do i get xdebug running on heroku?
I usually use heroku for testing so I need xdebug

@piwii
Copy link

piwii commented Feb 12, 2018

It can be a very nice feature because it is impossible de debug dyno application.
The only way to debug is to add log, but for my problem the bug is in third part code so i can't put log on it.
I am really lost, i don't know how to find my bug. Everything goes well in dev environment.

@martijngastkemper
Copy link
Contributor

I didn't try it myself, but you can build custom packages. I think that's the way to add xdebug to your app.

@dzuelke
Copy link
Contributor

dzuelke commented Feb 13, 2018

Yeah, that's the recommended way for the moment. Heroku Exec currently only has the ability to forward local ports to a dyno, not the inverse, which would be needed for Xdebug remote debugging (as Xdebug's only mode for that is having PHP connect to the IDE, not vice versa as with e.g. Java or Node).

https://github.com/Incenteev/heroku-php-exts is an example repo with several additional extensions (although they're all for cedar-14 only, and ext-amqp is now supported out of the box on heroku-16).

Note that you do not have to run a forked buildpack to use your own packages.

@abarke
Copy link

abarke commented Apr 3, 2020

In our use case xdebug is required by phpunit to generate code coverage reports:
https://stackoverflow.com/questions/35811503/laravel-5-phpunit-and-no-code-coverage-driver-available

Would it be simple enough to simply make the xdebug.so extension available on the heroku-18 stack when building it? or perhaps to post install the extension via sudo apt-get install php-xdebug ?

Perhaps a new environment variable could be implemented?
e.g. HEROKU_POST_INSTALL=sudo apt-get install php-xdebug
This would need to be executed during build time due to the permissions required I assume?

Thinking out of the box... couldn't one use the postdeploy script in the app.json or the post-install-cmd from composer.json to solve this? Or would this not allow sudo operations?

I recently tried this extension for VSCode to remote debug a Python app... if this would be possible using heroku exec this would be a killer feature for remote debugging Python, Java, PHP etc. in heroku containers or docker containers as the VSCode server resides in the container and forwards the data back over the SSH connection to your IDE: https://code.visualstudio.com/docs/remote/ssh

@alessandrodipierro
Copy link

alessandrodipierro commented Apr 3, 2020

Unfortunately for PHP debugging it is necessary that the server calls the IDE and not vice versa as for the other languages ​​mentioned. At the moment it is not allowed by heroku exec, so the addition of the extension would not be enough.

@abarke
Copy link

abarke commented Apr 3, 2020

Yes however my primary use case is that xdebug is used as a dependency for phpunit that doesnt require the remote debug port as far as I know or perhaps it uses it locally.

Question: Are heroku containers not allowed to open remote ports? I doubt that is the case otherwise I wouldn't be able to connect to my redis instance.

Now for the other use case of remote debugging using an IDE it should be enough to setup a SSH tunnel to the container and then running the VSCode server there. This means that the remote port would not be neccessary... the remote ip would be set to 127.0.0.1 and port 9000 as the VSCode server is running locally. The VSCode server would then proxy back the data via the SSH tunnel using whatever method it does. It would be an interesting PoC for Heroku im sure.

Some people have already had success over SSH:
xdebug/vscode-php-debug#360

@alessandrodipierro
Copy link

What you say is correct, but it is not possible to forward the local (non-public) port of the IDE. To make it work, the PC port 9000 would have to be published on the internet.

@abarke
Copy link

abarke commented Apr 3, 2020

Indeed. However it would nice to see a PoC of this VSCode Remote SSH extension working on heroku using exec and that would require that xdebug is installed. This would definitely be an elegant solution to debugging php applications remotely: https://code.visualstudio.com/docs/remote/ssh

The other reason for the extension as mentioned above would be phpunit.

@dzuelke isn't there a more elegant solution to post installing pecl extensions? Seems bizzare.

@rbaarsma
Copy link

rbaarsma commented Jul 6, 2020

Why doesn't heroku simply allow "ext-xdebug": "*", in the composer.json's require-dev section? For prod builds this is not used and xdebug can be disallowed, but for CI tests, composer is installed with --dev and then xdebug should be allowed as well

@dzuelke
Copy link
Contributor

dzuelke commented Jul 21, 2020

The issue is that we want to, under normal circumstances, avoid people having ext-xdebug running in their production environments. People will specify it in require, forget about it, and push.

I'll have a ponder. The really useful case would be an ability to debug remotely, but as has been pointed out, heroku ps:forward can only forward a local port to a dyno, not vice versa, so that won't work for PHP.

@abarke
Copy link

abarke commented Oct 1, 2020

The issue is that we want to, under normal circumstances, avoid people having ext-xdebug running in their production environments. People will specify it in require, forget about it, and push.

I'll have a ponder. The really useful case would be an ability to debug remotely, but as has been pointed out, heroku ps:forward can only forward a local port to a dyno, not vice versa, so that won't work for PHP.

Does this also apply to the VS Code server running remotely on the server? In this use case xdebug and vs code server will both be running on the remote server and the ports xdebug uses for debugging will not need to leave the server/container. The question is, does the VS code server work over heroku exec? Im not aware of what ports/architecture/requirements that has.

Another use case has just popped up. We are currently using buildpacks.io pack cli to launch a docker container for local development. Setting up the remote php interpreter in the docker container is easy with PhpStorm, however the only thing missing now is the xdebug extension again! Can someone pls pls pls implement this as is the missing part of the puzzle currently for us 🙂

@nileio
Copy link

nileio commented Jul 19, 2021

I also would like to use xdebug in dev only, perhaps strictly specify under require-dev and then enable it. xdebug simply initiaties the request to remote server so I dont see what is the issue of enabling it ? can someone provides an update on this please ? also you one can use a solution such as ngrok to forward tcp to the local running IDE @abarke

@felegy
Copy link

felegy commented Aug 15, 2021

Hi all!

My use case is in below:

I built a docker image for heroku debugging and I built xdebug from source.

Dockerfile:

ARG STACK_VERSION=20
ARG USER_NAME=hvg-dev
ARG UID=1001
FROM heroku/heroku:${STACK_VERSION}-build
ARG STACK_VERSION
ARG USER_NAME
ARG UID
ARG STACK=heroku-${STACK_VERSION}
ARG JQ_VERSION=1.6
ARG YQ_VERSION=4.11.1
ARG XDEBUG_VERSION=3.0.4

COPY ./bashrc /tmp/bashrc
COPY ./entrypoint.sh /
RUN useradd -M ${USER_NAME}  -d /app --uid ${UID}; \
    cat /tmp/bashrc >> /etc/profile; rm /tmp/bashrc; \
    mkdir -p /app /workspace; chown -R ${USER_NAME}:${USER_NAME} /app /workspace; \
    chmod a+x /entrypoint.sh;

USER ${USER_NAME}
WORKDIR /workspace

RUN mkdir -p bin; \
    curl -fsSL https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64 > bin/jq; \
    chmod a+x bin/jq; \
    curl -fsSL https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_amd64 > bin/yq; \
    chmod a+x bin/yq;

COPY --chown=${USER_NAME}:${USER_NAME} ./composer.json /tmp/composer.json
COPY --chown=${USER_NAME}:${USER_NAME} ./xdebug-install.sh /tmp/xdebug-install.sh

RUN s3_url="https://lang-php.s3.amazonaws.com/dist-${STACK}-stable/"; \
    curl -fsSL "${s3_url}php-min-7.4.21.tar.gz" | tar -xz -C .; \
    PATH="$(pwd)/bin:$PATH"; \
    curl -fsSL -o bin/composer https://getcomposer.org/download/2.1.4/composer.phar; \
    chmod a+x bin/composer; \
    chmod a+x /tmp/xdebug-install.sh; \
    php_version=$(cat /tmp/composer.json | bin/jq '.require .php' --raw-output); \
    composer init --name "heroku/dev" --type project --require="php:$php_version" --stability=stable --no-interaction 2>/dev/stdout; \
    composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction 2>/dev/stdout; \
    rm -rf ./vendor; \
    php_modules=$(cat /tmp/composer.json | bin/jq '.require | keys []' --raw-output | grep ext-); \
    for m in $php_modules; do composer require --no-install --ignore-platform-reqs $m:* 2>/dev/stdout; done; \
    mkdir -p /tmp/buildpack/php /tmp/build_cache /tmp/env; \
    curl -fsSL https://buildpack-registry.s3.amazonaws.com/buildpacks/heroku/php.tgz | tar -xz -C /tmp/buildpack/php; \
    echo "web: tail -f /dev/null" >> Procfile; \
    /tmp/buildpack/php/bin/compile $(pwd) /tmp/build_cache /tmp/env 2>/dev/stdout; \
    PATH="/workspace/.heroku/php/bin:$PATH"; \
    /tmp/xdebug-install.sh 2>/dev/stdout; \
    rm -rf /tmp/* /app/*

WORKDIR /app

ENV STACK=${STACK}
ENV PORT=3000

ENTRYPOINT [ "/entrypoint.sh" ]

xdebug-install.sh:

#!/usr/bin/env bash

# Define directories.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

XDEBUG_VERSION=${XDEBUG_VERSION-3.0.4}

if [ "$STACK" != "heroku-20" ] && [ "$STACK" != "heroku-18" ]; then
	echo "Need heroku-20 or heroku-18 stack"
	exit 0
fi

# echo colors
LED='\033[0;34m'
OK='\033[0;32m'
NC='\033[0m' # No Color
#############

###########################################################################
# COMPILE PHP xDebug
###########################################################################

XDEBUG_RELEASE_URI="https://xdebug.org/files/xdebug-$XDEBUG_VERSION.tgz";
SRC_PATH="/tmp";
XDEBUG_SRC_PATH=$SRC_PATH/xdebug-$XDEBUG_VERSION

echo -e "${LED}XDEBUG${NC} Download $XDEBUG_RELEASE_URI ..."
mkdir -p $XDEBUG_SRC_PATH
curl -# $XDEBUG_RELEASE_URI| tar --warning=none -xz -C $SRC_PATH
echo -e "${OK}done${NC}"

# Build from repo
#echo -e "${LED}XDEBUG${NC} Cloning source to $XDEBUG_SRC_PATH ..."
#git clone git://github.com/xdebug/xdebug.git $XDEBUG_SRC_PATH
#echo -e "${OK}done${NC}"

echo -e "${LED}XDEBUG${NC} Compile at $XDEBUG_SRC_PATH ..."
cd $XDEBUG_SRC_PATH
echo $PWD

LOGFILE=/tmp/xdebug_build.log
echo -e "`date +%H:%M:%S` : Starting work" >> $LOGFILE
phpize > $LOGFILE 2>&1
./configure --enable-xdebug  > $LOGFILE 2>&1
make -k > $LOGFILE 2>&1
echo -e "${OK}done${NC}"

###########################################################################
# INSTALL PHP xDebug
###########################################################################

EXTENSION_PATH=$( php-config --extension-dir );
LIB_PATH="$( php-config --prefix )/lib"
INSTALL_PATH=$( php-config --ini-dir );
XDEBUG_INI="020-xdebug.ini";
XDEBUG_INI_PATH=$SCRIPT_DIR/$XDEBUG_INI;

echo -e "${LED}XDEBUG${NC} Install bin to $EXTENSION_PATH ..."
cp -v modules/*.so $EXTENSION_PATH
cp -v modules/*.la $LIB_PATH
echo -e "${OK}done${NC}"

echo -e "${LED}XDEBUG${NC} Install ini to $INSTALL_PATH ..."
echo "zend_extension = xdebug.so" >> $XDEBUG_INI_PATH
cp -v $XDEBUG_INI_PATH $INSTALL_PATH/$XDEBUG_INI
echo -e "${OK}done${NC}"

echo -e "${LED}XDEBUG${NC} All Install ${OK}done${NC}"
###########################################################################

composer.json:

{
    "name": "heroku/dev",
    "type": "project",
    "require": {
        "php": "^7.4.0"
    },
    "minimum-stability": "stable",
    "require-dev": {
        "heroku/heroku-buildpack-php": "*"
    }
}

xdebug.ini:

; Xdebug
[XDebug]
xdebug.max_nesting_level = 256
xdebug.show_exception_trace = 0

xdebug.mode = debug
xdebug.start_with_request = yes

#Replace host.docker.internal to your computers IP address if linux
xdebug.client_host = ${XDEBUG_HOST}

bashrc:

# prompt
export PS1='\[\033[01;34m\]\w\[\033[00m\] \[\033[01;32m\]$ \[\033[00m\]'

# profile feature switch
if [ -d $HOME/.profile.d ]; then
  for i in $HOME/.profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

entrypoint.sh:

#!/usr/bin/env sh

COMMAND=$*

#BASEDIR=$(dirname "$0")

if [ ! -d /app/.heroku ]; then
    cp -r /workspace/.heroku /app
fi

if [ ! -d /app/.profile.d ]; then
    cp -r /workspace/.profile.d /app 
fi

XDEBUG_ENABLE=${XDEBUG_ENABLE-0}
export XDEBUG_ENABLE

rm -f /app/.heroku/php/etc/php/conf.d/999-xdebug.ini

if [ "$XDEBUG_ENABLE" = 1 ]; then
    ln -sn $(pwd)/xdebug.ini /app/.heroku/php/etc/php/conf.d/999-xdebug.ini
fi

PATH="/workspace/bin:$PATH"
export PATH

HISTFILE=${HISTFILE-/tmp/.bash_history}
export HISTFILE

keys=$(yq e '. | keys' Procfile | cut -c 3-)

for key in $keys; do 
    echo '#!/usr/bin/env bash' > "/workspace/bin/$key"
    yq e ".$key" Procfile >> "/workspace/bin/$key"
    chmod +x "/workspace/bin/$key"
done 

bash -l -c "$COMMAND"

Procfile:

web: vendor/bin/heroku-php-nginx .

docker-compose.yml:

version: "3.8"

services:
  app:
    ports:
      - ${PORT-3000}:${PORT-3000}
    command: web
    build: .

docker-compose.override.yml:

version: "3.8"
services:
  app:
    build:
      args:
        UID: ${UID-1001}
    environment:
      PORT: ${PORT-3000}
      XDEBUG_HOST: ${XDEBUG_HOST-host.docker.internal}
      XDEBUG_ENABLE: ${XDEBUG_ENABLE-1}
    volumes:
      - ./:/app

In Linux Host requires settings below:

echo "UID=$(id -u)" >> .env
echo "XDEBUG_HOST=$(hostname -I | awk '{print $1}')" >> .env

For using as heroku build step modify composer.json like below:

{
    "name": "heroku/dev",
    "type": "project",
    "require": {
        "php": "^7.4.0"
    },
    "minimum-stability": "stable",
    "require-dev": {
        "heroku/heroku-buildpack-php": "*"
    },
    "scripts": {
        "post-install-cmd": [
            "bash xdebug-install.sh"
        ]
    }
}

And now push to heroku:

git push heroku main                 
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 2 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 675 bytes | 675.00 KiB/s, done.
Total 6 (delta 4), reused 0 (delta 0), pack-reused 0
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Building on the Heroku-20 stack
remote: -----> Using buildpack: heroku/php
remote: -----> PHP app detected
remote: -----> Bootstrapping...
remote: -----> Installing platform packages...
remote:        - php (7.4.22)
remote:        - composer (2.1.5)
remote:        - apache (2.4.48)
remote:        - nginx (1.20.1)
remote: -----> Installing dependencies...
remote:        Composer version 2.1.5 2021-07-23 10:35:47
remote:        Installing dependencies from lock file
remote:        Verifying lock file contents can be installed on current platform.
remote:        Nothing to install, update or remove
remote:        Generating optimized autoload files
remote:        > bash xdebug-install.sh
remote:        XDEBUG Download https://xdebug.org/files/xdebug-3.0.4.tgz ...
remote: ######################################################################## 100.0%
remote:        done
remote:        XDEBUG Compile at /tmp/xdebug-3.0.4 ...
remote:        /tmp/xdebug-3.0.4
remote:        done
remote:        XDEBUG Install bin to /app/.heroku/php/lib/php/extensions/no-debug-non-zts-20190902 ...
remote:        'modules/xdebug.so' -> '/app/.heroku/php/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so'
remote:        'modules/xdebug.la' -> '/app/.heroku/php/lib/xdebug.la'
remote:        done
remote:        XDEBUG Install ini to /app/.heroku/php/etc/php/conf.d ...
remote:        '/tmp/build_f8f51b83/020-xdebug.ini' -> '/app/.heroku/php/etc/php/conf.d/020-xdebug.ini'
remote:        done
remote:        XDEBUG All Install done
remote: -----> Preparing runtime environment...
remote: -----> Checking for additional extensions to install...
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote: 
remote: -----> Compressing...
remote:        Done: 15.5M
remote: -----> Launching...
remote:        Released v6
remote:        https://felegy-heroku-xdebug.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy... done.
To https://git.heroku.com/felegy-heroku-xdebug.git
   1ff79a8..0ae0c7d  main -> main

Check my phpinfo: https://felegy-heroku-xdebug.herokuapp.com/phpinfo.php

@nileio
Copy link

nileio commented Aug 16, 2021

@felegy thanks for sharing. what i did in dokku is to use a plugin calld apt-packages which enable you to inject additional binaries inside the container - i used it to inject php-xdebug which automatically installs xdebug 2.9 still compatible with php 7.4 , and then used pre-deploy scripts to copy the final xdebug.so file to the correct heroku php ini location. It works perfectly but yeah it is a bit hacky! advantage is I didnt have to build from scratch
thanks for sharing your setup, this is great help

brunocantuaria pushed a commit to studiohyperset/heroku-buildpack-php that referenced this issue Jul 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants