At first, it looked like a GitLab permission problem or an issue with the package itself. But SSH to GitLab worked from the host, so instead of changing credentials I started comparing the host environment with the Docker workspace.
In my setup, Composer runs inside a Laradock workspace. That is where I found the actual problem: the container could not see the SSH Agent that was already available on the host.
Symptom: Composer asks for GitLab credentials
The issue appeared during a normal update of a private Composer package.
dcomposer update avn/laravel-localization --with-dependenciesInstead of updating the package, Composer tried to access the private GitLab repository and could not authenticate over SSH.
It then offered to create credentials and asked for a username and password. That was an important clue: Composer was not necessarily the problem. It simply could not use the GitLab access method that already worked on my host.
Permission denied (publickey). Username:Password:Checking SSH on the host
I started with the simplest check: whether SSH to GitLab worked outside Docker at all.
ssh -T git@gitlab.comWelcome to GitLab, @xmarynkam!What does the Docker workspace see?
I repeated the same check inside the Laradock workspace where Composer actually runs.
docker compose exec workspace-85 ssh -T git@gitlab.comgit@gitlab.com: Permission denied (publickey).That made the difference obvious: GitLab SSH worked on the host but failed inside the container on the same machine.
The next thing I checked was the SSH Agent. My keys were loaded correctly on the host, while SSH_AUTH_SOCK inside the Docker workspace was empty.
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"ssh-add -lHost SSH key → ssh-agent → GitLab ✓ Docker Composer → Git → SSH ↓ no SSH agent ✗Host ssh-agent │ │ mounted socket ▼Docker workspace │ └── Git / Composer → GitLab ✓The real issue was SSH_AUTH_SOCK
SSH Agent runs as a separate process on the host and provides access to loaded SSH keys. Applications communicate with it through a socket whose path is exposed through SSH_AUTH_SOCK.
A Docker container does not automatically receive that socket. Git inside my workspace therefore had no way to use the SSH Agent even though everything was configured correctly on the host.
That was the key point for me: I did not need to copy an SSH key into the container. I needed to give the container access to the SSH Agent that was already running on the host.
Forwarding the SSH Agent into Laradock
I moved the SSH Agent configuration into a reusable Docker Compose anchor so I could apply it to several PHP workspaces without duplicating it.
x-local-ssh-agent: &local-ssh-agent environment: SSH_AUTH_SOCK: /ssh-agent volumes: - "${SSH_AUTH_SOCK}:/ssh-agent"The host socket is mounted inside the container as /ssh-agent, and SSH_AUTH_SOCK inside the workspace points to that location.
I use several Laradock workspaces for different PHP versions, so I applied the same anchor to every CLI workspace.
services: workspace: <<: [*local-host-config, *local-ssh-agent] workspace-84: <<: [*local-host-config, *local-ssh-agent] workspace-85: <<: [*local-host-config, *local-ssh-agent]Recreating the workspace after the Compose change
docker compose up -d \ --force-recreate \ --no-deps \ workspace-85Verifying SSH Agent inside the container
After recreating the container, I checked the SSH Agent before trying Composer again. This makes it much easier to see whether the infrastructure part is actually fixed.
docker compose exec --user laradock workspace-85 sh -lc 'echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"ssh-add -l'Once the keys were visible inside the workspace, I tested the direct SSH connection to GitLab again.
docker compose exec --user laradock workspace-85 \ ssh -o StrictHostKeyChecking=accept-new -T git@gitlab.comWelcome to GitLab, @xmarynkam!Only then I went back to Composer
After that, I repeated the same Composer command that originally failed. This time Composer could access the private GitLab repository through Git and update the package without asking for a username or password.
dcomposer itself is part of my local multi-PHP workflow with dphp, dartisan, and dcomposer, where the correct Laradock workspace is selected automatically for each project.
For me, this was a good example of why it helps to debug the problem layer by layer:
GitLab SSH first,
Docker next,
then SSH Agent,
and Composer only after that.
dcomposer update avn/laravel-localization --with-dependenciesWhat I would not do here
Copy a private SSH key into a Docker image or container.
Store a GitLab password inside the container.
Enter a Personal Access Token every time Composer asks for credentials.
Treat it as a Composer problem before checking plain Git and SSH access from the same environment.
What I took away from this case
In my case, Composer was only showing the symptom. The actual problem existed one layer lower: Git inside Docker could not access the host SSH Agent.
Once I forwarded SSH_AUTH_SOCK through Docker Compose and mounted the agent socket into the Laradock workspace, the same SSH key worked both on the host and inside the container.
That configuration is now shared by my PHP workspaces, and private Composer packages can be updated without copying SSH keys or storing separate GitLab credentials inside Docker.



