-
This is not a credential or nginx upload-size problem. Both failing steps never complete a TCP handshake:
dial tcp <server public IP>:443: i/o timeoutWhy it fails in the job, but works on the agent CLI
- Build Image always uses the
onedevbuildx builder. That builder is a BuildKit container, not the default Docker driver. - Push Image runs
craneinside the1dev/cranecontainer. - Those containers resolve the registry host to the public IP and then cannot open port 443.
The same
docker buildx buildwithout--builder onedevuses the host / default builder network, which can reach the registry. Isolated job/builder containers often cannot. That is typical hairpin NAT or Docker-bridge routing when the agent is on the same host or LAN as OneDev.Administration → System Settings → server URL (and the host in image tags / registry logins) must be reachable from Docker containers, not only from the agent host. See working with container images.
Confirm on the agent
docker run --rm curlimages/curl -I https://<onedev-host>/v2/ docker run --rm --network host curlimages/curl -I https://<onedev-host>/v2/If the first times out and the second works, this diagnosis is confirmed.
What to change
-
Point jobs at a name or private IP that containers can route to (split-horizon DNS or an internal hostname). Tags and registry login must use that same host. Prefer
@server@for tags. For built-in registry login use@server_url@, user@job_token@, and an access-token secret with package write permission. -
Recreate the
onedevbuilder on the agent with host networking (same network as the command that already works):
docker buildx rm onedev docker ps -a | grep buildx_buildkit_ # remove any leftover builder container docker buildx create --name onedev --driver docker-container --driver-opt network=host- For Push Image, add a host mapping in the docker executor Run Options, for example
--add-host <onedev-host>:<ip-reachable-from-containers>.
Do not use
localhostor127.0.0.1as the registry host from these steps.Nginx
client_max_body_sizeis not involved here (the connection never reaches nginx). After containers can connect, keep a large body size and generousproxy_read_timeout/proxy_send_timeoutfor layer uploads.If the agent host only reaches that public IP via an HTTP forward proxy, also configure the builder and crane as in docker registry proxy. The log shows a direct TCP dial to the public IP, so missing proxy settings are less likely than container routing.
If you later use HTTP or a self-signed cert, follow insecure docker registry.
- Build Image always uses the
-
Thanks for the fast and elaborate reply.
Confirm on the agent
docker run --rm curlimages/curl -I https:///v2/ docker run --rm --network host curlimages/curl -I https:///v2/
I started an SSH session into the bare-metal host that hosts the dockerized OneDev agent and executed both commands. -> Both commands succeed with a 401 status
From there I started a bash session in the dockerized OneDev agent using: docker exec -it CodeSpaceAgent1 /bin/bash
From this bash prompt I executed both commands again. -> Both commands succeed with a 401 status.
My OneDev dockerized agent is on a different machine and different LAN than my OneDev server instance. The agent is running on an internal (behind firewall and NAT) machine. The OneDev server is on a publicly reachable VPS with a routable internet IPv4 address. No forward proxies in play at the agent side. Certificates are current LetsEncrypt certificates.
-
Those results rule out hairpin NAT. With the agent on a different LAN and both host-network and default-bridge containers getting HTTP 401, the host can reach the public registry.
Those two
docker runcommands still do not use the networks the failing steps use:- Push Image runs
cranein a job step container on a per-job user-defined Docker network (build-<executor>-…), not on the defaultdocker0bridge and not on host network. - Build Image always uses
--builder onedev. That builder is a BuildKit container (docker-containerdriver). The push is made from that container’s network. The samedocker buildx buildwithout--builder onedevuses the default Docker driver and pushes from the daemon/host namespace, which is why it works from the agent CLI.
docker runwithout--networkuses the default bridge. That is a different path.Please run these on the agent host (same Docker daemon the jobs use):
# 1) User-defined network (same class of network as job step containers) docker network create onedev-egress-test docker run --rm --network onedev-egress-test curlimages/curl -v -I https://<onedev-host>/v2/ docker network rm onedev-egress-test # 2) IPv4 vs IPv6 (crane and buildkit are Go; they do not Happy-Eyeballs like curl) getent ahosts <onedev-host> docker run --rm curlimages/curl -4 -I https://<onedev-host>/v2/ docker run --rm curlimages/curl -6 -I https://<onedev-host>/v2/ # 3) Existing onedev builder container docker ps -a | grep buildx_buildkitIf (1) times out, job networks cannot egress. Typical causes are firewall/UFW/firewalld masquerading only
docker0, a DROP FORWARD policy, or a user-defined subnet overlapping a VPN/LAN route to the VPS.If (2) IPv6 times out while IPv4 returns 401, that matches the ~30s
dial tcp … i/o timeoutfrom crane and buildkit.Workarounds
Recreate the builder with host networking (same network as the CLI command that already works):
docker buildx rm onedev docker ps -a | grep buildx_buildkit # remove any leftover builder container docker buildx create --name onedev --driver docker-container --driver-opt network=hostIf the agent runs in Docker, create this builder from inside the agent container (or mount
~/.docker/buildxas in insecure docker registry) so the agent sees the same builder.For Push Image, either add
--network hostto the remote docker executor Run Options (this overrides the job network; job services will not see each other), or fix NAT/FORWARD so user-defined bridges can reach the VPS.Do not use
localhostas the registry host. Prefer@server@for tags. For built-in registry login use@server_url@, user@job_token@, and an access-token secret with package write permission.Please paste the output of tests (1) and (2).
- Push Image runs
-
root@CodeSpaceAgent1:/agent/bin# docker network create onedev-egress-test 5c592171c7f2e1474bd35d6ba28875ebbe2baf88bbdddf0524186916b997d2d3 root@CodeSpaceAgent1:/agent/bin# docker run --rm --network onedev-egress-test curlimages/curl -v -I https://[URL]/v2/ * Host [URL]:443 was resolved. * IPv6: (none) * IPv4: [Correct Server IP] * Trying [Correct Server IP]:443... * ALPN: curl offers h2,http/1.1 } [5 bytes data] * TLSv1.3 (OUT), TLS handshake, Client hello (1): } [1566 bytes data] * SSL Trust Anchors: * CAfile: /cacert.pem { [5 bytes data] * TLSv1.3 (IN), TLS handshake, Server hello (2): { [122 bytes data] * TLSv1.3 (IN), TLS change cipher, Change cipher spec (1): { [1 bytes data] * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): { [19 bytes data] * TLSv1.3 (IN), TLS handshake, Certificate (11): { [4339 bytes data] * TLSv1.3 (IN), TLS handshake, CERT verify (15): { [520 bytes data] * TLSv1.3 (IN), TLS handshake, Finished (20): { [52 bytes data] * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): } [1 bytes data] * TLSv1.3 (OUT), TLS handshake, Finished (20): } [52 bytes data] * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / x25519 / RSASSA-PSS * ALPN: server accepted h2 * Server certificate: * subject: CN=[URL] * start date: Sep 3 19:16:38 2026 GMT * expire date: Dec 2 19:16:37 2026 GMT * issuer: C=US; O=Let's Encrypt; CN=YR2 * Certificate level 0: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption * Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption * Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption * Certificate level 3: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption * subjectAltName: "[URL]" matches cert's "[URL]" * OpenSSL verify result: 0 * SSL certificate verified via OpenSSL. * Established connection to [URL] ([Correct Server IP] port 443) from 172.23.0.2 port 43754 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 0* using HTTP/2 * [HTTP/2] [1] OPENED stream for https://[URL]/v2/ * [HTTP/2] [1] [:method: HEAD] * [HTTP/2] [1] [:scheme: https] * [HTTP/2] [1] [:authority: [URL]] * [HTTP/2] [1] [:path: /v2/] * [HTTP/2] [1] [user-agent: curl/8.22.0] * [HTTP/2] [1] [accept: */*] } [5 bytes data] > HEAD /v2/ HTTP/2 > Host: [URL] > User-Agent: curl/8.22.0 > Accept: */* > * Request completely sent off } [5 bytes data] * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): { [57 bytes data] * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): { [57 bytes data] < HTTP/2 401 < server: nginx/1.27.3 < date: Fri, 04 Sep 2026 13:43:33 GMT < content-length: 0 < docker-distribution-api-version: registry/2.0 < www-authenticate: Bearer realm="https://[URL]/v2/token",service="onedev",scope="*" HTTP/2 401 < strict-transport-security: max-age=31536000 < { [0 bytes data] 0 0 0 0 0 0 0 0 0 * Connection #0 to host [URL]:443 left intact server: nginx/1.27.3 date: Fri, 04 Sep 2026 13:43:33 GMT content-length: 0 docker-distribution-api-version: registry/2.0 www-authenticate: Bearer realm="https://[URL]/v2/token",service="onedev",scope="*" strict-transport-security: max-age=31536000 root@CodeSpaceAgent1:/agent/bin# docker network rm onedev-egress-test onedev-egress-test root@CodeSpaceAgent1:/agent/bin# getent ahosts [URL] [Correct Server IP] STREAM vps01.wiermans.net [Correct Server IP] DGRAM [Correct Server IP] RAW root@CodeSpaceAgent1:/agent/bin# docker run --rm curlimages/curl -4 -I https://[URL]/v2/ % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 HTTP/2 401 0 0 0 0 0 0 0 0 0 0 server: nginx/1.27.3 date: Fri, 04 Sep 2026 13:45:18 GMT content-length: 0 docker-distribution-api-version: registry/2.0 www-authenticate: Bearer realm="https://[URL]/v2/token",service="onedev",scope="*" strict-transport-security: max-age=31536000 root@CodeSpaceAgent1:/agent/bin# docker run --rm curlimages/curl -6 -I https://[URL]/v2/ curl: (6) Could not resolve host: [URL] -
Those results close the last two connectivity guesses:
- A user-defined Docker network can reach the registry (HTTP 401, TLS OK, source
172.23.0.2). Job-network egress is not blocked. - The hostname is IPv4-only.
curl -6failing to resolve is expected (no AAAA). This is not an IPv6 Happy-Eyeballs timeout.
A generic
curlcontainer is still not the process that fails. Build Image pushes from the persistentonedevBuildKit container (docker-containerdriver). That network is independent ofonedev-egress-test. Push Image runscranein1dev/crane:1.0.0on the per-jobbuild-<executor>-…network. Test (3) was not pasted.Please run these inside the agent container (same Docker daemon the jobs use):
# Builder used by Build Image docker buildx ls docker ps -a | grep buildx_buildkit # If a buildkit container exists, use ITS network namespace docker run --rm --network container:<buildkit-container-name> curlimages/curl -v -I https://<onedev-host>/v2/ # Same image as Push Image docker run --rm --network onedev-egress-test 1dev/crane:1.0.0 catalog <onedev-host>crane catalogonly needs to get past/v2/. If that printsdial tcp … i/o timeout, the problem is the crane/BuildKit runtime, not the job bridge.Workaround that matches the CLI path that already works
Recreate the builder with host networking from inside the agent (so the agent sees the same builder). If you create it only on the host, mount
~/.docker/buildxinto the agent as in insecure docker registry.docker buildx rm onedev docker ps -a | grep buildx_buildkit # remove any leftover builder container docker buildx create --name onedev --driver docker-container --driver-opt network=host --useThen retry Build Image.
For Push Image, add
--network hostto the remote docker executor Run Options. That overrides the job network; job services will not see each other.Prefer
@server@in tags. For built-in registry login use@server_url@, user@job_token@, and an access-token secret with package write permission.Please paste
docker buildx ls, the buildkitdocker psline, the shared-namespace curl if a builder exists, and thecrane catalogoutput. - A user-defined Docker network can reach the registry (HTTP 401, TLS OK, source
-
Test 3 yielded no results:
root@CodeSpaceAgent1:/agent/bin# docker ps -a | grep buildx_buildkit root@CodeSpaceAgent1:/agent/bin#Your test output:
root@CodeSpaceAgent1:/agent/bin# docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS default* docker \_ default \_ default running v0.29.0 linux/amd64 (+3) root@CodeSpaceAgent1:/agent/bin# docker ps -a | grep buildx_buildkit root@CodeSpaceAgent1:/agent/bin# docker run --rm --network onedev-egress-test 1dev/crane:1.0.0 catalog [URL] Unable to find image '1dev/crane:1.0.0' locally 1.0.0: Pulling from 1dev/crane 9d95e77b6d6f: Pull complete 1e3d9b7d1452: Pull complete 4aa0ea1413d3: Pull complete 96266735468f: Pull complete a7ca0d9ba68f: Pull complete fe5ca62666f0: Pull complete b02a7525f878: Pull complete fcb6f6d2c998: Pull complete 2758d0c31c8c: Pull complete 5627a970d25e: Pull complete 7f1acc538748: Pull complete 7c881f9ab25e: Pull complete 08553ba93cfe: Pull complete e8c73c638ae9: Pull complete 250c06f7c38e: Pull complete 71b42c1dc2b2: Download complete Digest: sha256:2d21b3c0d5533d4f6e722a05f1ccb078d4a414a4547ccdf881122cd2c6eb3103 Status: Downloaded newer image for 1dev/crane:1.0.0 docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "catalog": executable file not found in $PATH Run 'docker run --help' for more information root@CodeSpaceAgent1:/agent/bin# docker run --rm --network onedev-egress-test 1dev/crane:1.0.0 crane catalog [URL] docker: Error response from daemon: failed to set up container networking: network onedev-egress-test not found Run 'docker run --help' for more information root@CodeSpaceAgent1:/agent/bin# docker network create onedev-egress-test c94cfbd795f84bc16d47d00479938bd12135bf3adbee8589c59d2572530b8b2f root@CodeSpaceAgent1:/agent/bin# docker run --rm --network onedev-egress-test 1dev/crane:1.0.0 crane catalog [URL] Error: reading tags for [URL]: GET https://[URL]/v2/_catalog?n=1000: UNSUPPORTED: root@CodeSpaceAgent1:/agent/bin#I skipped test #2, because there was no buildkit found. I also suspected a small error in your 3rd command since it threw an error. Hence, I added the 'crane' command before the 'catalog'. I also re-added the onedev-egress-test network since it was deleted as part of earlier tests.
-
Those results close the crane/job-network question.
UNSUPPORTEDmeans crane reached OneDevGET /v2/_catalogis not implemented by the built-in registry, soUNSUPPORTEDis the expected HTTP response. Crane finished DNS, TCP, TLS, and HTTP on a user-defined network. That is not adial tcp … i/o timeout.The extra
craneprefix was correct:1dev/crane:1.0.0does not treatcatalogas the entrypoint.No
onedevbuilder right nowdocker buildx lsshowing onlydefault, and nobuildx_buildkitcontainer, means the persistent builder is not present at the moment. Build Image creates it on first use withdocker buildx create --name onedev(docker-containerdriver, default container network — not host, not the jobbuild-…network). It should remain after the step. If it is missing, Build Image has not run since a prune/reboot, the builder was removed, or the interactive shell’s$HOME/.docker/buildxis not the one the agent process uses.The
#16 exporting to image/pushing layers/dial tcp … i/o timeoutlog is buildx. That is Build Image with “Push to container registry”, not Push Image (crane pushlogs differently).What is still open
Every single-request test from the agent works (default bridge, user-defined network, host network, crane). A registry push is not a single request: BuildKit (and a real
crane push) open many parallelHEAD /v2/…/blobs/sha256:…connections. A firewall, conntrack table, or SYN limit that allows one curl but drops a burst of dials matches the 30s timeouts on those blob HEADs.What to do
- Recreate the builder with host networking inside the agent container (same Docker CLI the jobs use), then retry Build Image:
docker buildx rm onedev || true docker ps -a | grep buildx_buildkit # remove leftover builder containers if any docker buildx create --name onedev --driver docker-container --driver-opt network=host --use docker buildx lsIf
docker buildx lsstill does not showonedevafter create, the agent is using another buildx state (different$HOME). Create the builder as the same user the agent runs as, or mount that user’s~/.docker/buildxas in insecure docker registry.- After Build Image runs (even if it fails), immediately:
docker ps -a | grep buildx_buildkit docker run --rm --network container:<buildkit-container-name> curlimages/curl -v -I https://<onedev-host>/v2/-
Retry Push Image. Crane already reached
/v2/. If push still times out, add--network hostto the remote docker executor Run Options (job services will no longer share a network). -
Prefer
@server@in the image tag. For built-in registry login use@server_url@, user@job_token@, and an access-token secret with package write permission. Do not puthttps://in the image tag host. -
On nginx, keep a large
client_max_body_sizeand generousproxy_read_timeout/proxy_send_timeoutonce TCP works. Also check whether the VPS firewall rate-limits concurrent connections from the agent.
Please paste
docker buildx lsafter the create, the Build Image retry result, and (if the builder container exists) the shared-namespace curl. -
After creation:
root@CodeSpaceAgent1:/agent/bin# docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS onedev* docker-container \_ onedev0 \_ unix:///var/run/docker.sock inactive default docker \_ default \_ default running v0.29.0 linux/amd64 (+3)Build fails the same way as before.
During the build, docker ps -a | grep buildx_buildkit run from inside the agent container yields zero results. After the build the docker buildx ls shows:
root@CodeSpaceAgent1:/agent/work# docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS onedev* docker-container \_ onedev0 \_ unix:///var/run/docker.sock inactive default docker \_ default \_ default running v0.29.0 linux/amd64 (+3) -
The builder you created was never used by the job.
inactiveafterdocker buildx createis expected. The firstdocker buildx build --builder onedevshould start a BuildKit container (buildx_buildkit_onedev0or similar) and flip that node torunning. Yours stayedinactive, anddocker psshowed no BuildKit container while the job was failing. So Build Image did not use this builder on the Docker daemon you are inspecting. That is why host networking changed nothing.Most likely: the job is not running on
CodeSpaceAgent1Single-request tests on this agent already succeed (curl HTTP 401, crane
UNSUPPORTED). A CLIdocker buildx buildwithout--builder onedevalso works here. The failure is stilldial tcp <public IP>:443: i/o timeoutfrom whatever actually runs the step.Please paste the first job-log line that looks like one of these:
Executing job (executor: …, agent: …)— Remote Docker Executor. Check the agent name. If it is not this agent, recreate the host-network builder on that agent.Executing job (executor: …, server: …, network: …)— Server Docker Executor on the OneDev VPS. Then this agent’s builder is irrelevant. The push runs in a BuildKit container on the VPS. A container on that VPS dialing the VPS’s own public IP is classic hairpin NAT and matches this timeout.
If it is the server executor, run this on the OneDev server (not this agent), as the OS user that runs the OneDev process (or mount that user’s
~/.docker/buildxinto the server container as in insecure docker registry):docker buildx rm onedev || true docker buildx create --name onedev --driver docker-container --driver-opt network=host --use docker buildx lsThen retry Build Image. Prefer a hostname those containers can route to (internal name or a container-reachable IP), not only the public one. Prefer
@server@in tags. For built-in registry login use@server_url@, user@job_token@, and an access-token secret with package write permission.For Push Image on that same executor, add
--network hostto Run Options (job services will no longer share a network).If the log shows this agent
OneDev copies
$HOME/.docker/buildxfrom the agent JVM (user.home/DOCKER_CONFIG), not necessarily your interactive root shell, into a temporaryDOCKER_CONFIGbeforedocker buildx create --name onedevanddocker buildx build --builder onedev.Inside the agent container:
echo "shell HOME=$HOME" ls -la /root/.docker/buildx /agent/.docker/buildx 2>/dev/null tr '\0' '\n' < /proc/1/environ | grep -E 'HOME|DOCKER' ps -o pid,user,args -C javaCreate the host-network builder with that same
HOME(example if the agent home is/agent):HOME=/agent docker buildx rm onedev || true HOME=/agent docker buildx create --name onedev --driver docker-container --driver-opt network=host --use HOME=/agent docker buildx lsWhile Build Image is in
#16 pushing layers(not after it fails, and not during Push Image):docker ps -a --format '{{.Names}} {{.Image}} {{.Status}}'Please paste the
Executing jobline, the HOME/process output, and thatdocker psduring the push. -
I am starting to feel stupid. I first tried creating an agent on the same server as the OneDev server, but that threw an error message (I do not remember which on). Then I decided to create an agent on another machine, assuming this one would be used for all subsequent work. But from the first lines of the log...
10:36:28 No job executor defined, auto-discovering... 10:36:28 Discovered server docker executor 10:36:28 Pending resource allocation... 10:36:28 Executing job (executor: auto-discovered, server: 127.0.0.1:5710, network: build-auto-discovered-34-13-3)... -
This is a common setup mix-up, not something you did wrong.
Connecting an agent does not make OneDev run jobs on it. An agent is only a worker that a Remote Docker Executor can select. With no job executor defined, OneDev auto-discovers what can run on the OneDev server itself. Docker is available there, so it picked Server Docker Executor.
That is what this line means:
Executing job (executor: auto-discovered, server: 127.0.0.1:5710, network: build-auto-discovered-34-13-3)...server: 127.0.0.1:5710is the OneDev process on the VPS, notCodeSpaceAgent1. The job network was created on the server Docker daemon. That is why every test on the remote agent succeeded, the builder you created there stayedinactive, and the push still timed out: Build Image / Push Image never ran on that agent.An agent on the same machine as OneDev often fails if
serverUrlislocalhostor127.0.0.1(the agent container cannot reach the server). Use a hostname or IP the agent container can route to. You do not need an agent on the OneDev host to run jobs there; that is what Server Docker Executor already does.So the timeout is hairpin NAT: a BuildKit (or crane) container on the VPS is dialing the VPS public IP on port 443.
Path 1 — run jobs on
CodeSpaceAgent1(what you intended)Follow Build farm with agents:
- Administration → Job Executors
- Add Remote Docker Executor and give it a name
- Optionally set Agent Selector to this agent
- Test and save
Once any executor is defined, auto-discover stops. If you add only this Remote Docker Executor, jobs go to the agent. The next job log should start with
Executing job (executor: …, agent: …). Your earlier curl/crane tests already show that agent can reach the registry.Path 2 — keep using the server executor (no agent required)
Do this on the OneDev server, as the OS user that runs OneDev (or mount that user’s
~/.docker/buildxinto the server container as in insecure docker registry):docker buildx rm onedev || true docker buildx create --name onedev --driver docker-container --driver-opt network=host --use docker buildx lsThen retry Build Image. Prefer a hostname those containers can route to (internal name or a container-reachable IP), not only the public one. Prefer
@server@in tags. For built-in registry login use@server_url@, user@job_token@, and an access-token secret with package write permission.For Push Image on that executor, add
--network hostto Run Options (job services will no longer share a network).Please say which path you want, then paste the new
Executing jobline and the push result. -
Glad that is working. Closing this question.
-
Previous Value Current Value Open
Closed
| Type |
Question
|
| Priority |
Normal
|
| Assignee | |
| Labels |
No labels
|
When I try to push my docker image to the onedev internal docker hub the build times out. The problem is consistent for the 'Docker Image / Build Image' as well as for the 'Docker Image / Push Image' step. Building the image to an OCI succeeds, but the pushing times out. The onedev server is behind a https-proxy (nginx) with no limit on upload size. Executing the same docker buildx build command (without the --builder onedev part) from the commandline of the agent works flawlessly. Credentials are supplied in the Registry Logins section of the step. I put in https://[URL] as the server, my login as the username and a token generated in my user account as the password.
Relevant log lines when using the 'Docker Image / Push Image' step:
Relevant log lines when using the 'Docker Image / Push Image' step:
What am I missing here?