fix(service): route the rybbit /api path to the backend

The Rybbit template had a proxy route only for the client, so the
/api requests of the browser got a 404 from the client and sign-up
and login failed. The backend now declares SERVICE_URL_RYBBIT_3001=/api
on the same host and keeps the /api prefix. The backend is listed
before the client, so SERVICE_URL_RYBBIT (used in BASE_URL) stays the
root URL.

Closes #9055

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-11-03 20:19:27 +01:00
co-authored by Claude Opus 5.5
parent f21acdc3e4
commit d3ef4d1c57
6 changed files with 45 additions and 18 deletions
+1
View File
@@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
- Send one request less to GitHub before each deployment and each list of repositories of a GitHub App. Before, Coolify always called `/zen` to compare its clock with GitHub before it requested an installation token, so a short network problem between the Coolify instance and GitHub failed the deployment with `cURL error 28: Connection timed out ... for https://api.github.com/zen`. Coolify now compares the clocks only when GitHub rejects a request, from the `Date` header of that response, and still shows "System time is out of sync with GitHub API time" ([#9785](https://github.com/coollabsio/coolify/issues/9785))
- Retry GitHub API reads, such as the repository lookup before each deployment, up to three times when GitHub answers with a 5xx error or the connection fails. Before, one `502` or one timeout from GitHub failed the deployment. Writes, such as pull request comments, are not retried ([#9785](https://github.com/coollabsio/coolify/issues/9785))
- Keep an application that uses a server only as an additional destination when you delete that server with **Delete all resources** or with `DELETE /api/v1/servers/{uuid}?force=true`. Before, Coolify deleted the application on all its servers, also after **Promote** made another server its main server. Coolify now removes the application only from the deleted server and stops its containers there. A server that has only such applications can be deleted without **Delete all resources**. The delete confirmation lists the resources that it deletes and the applications that keep running on another server
- Fix the sign-up and login of the Rybbit service template. The proxy sent all requests to the client container, so the `/api` requests of the browser got a 404 error. The template now routes `/api` on the same domain to the backend on port 3001, and keeps the `/api` prefix. For an existing Rybbit service, add `SERVICE_URL_RYBBIT_3001=/api` to the `rybbit_backend` service, move `rybbit_backend` above `rybbit` in the Docker Compose file, set **Path prefixes** to **Keep prefixes** in the advanced settings of the backend, and redeploy the service ([#9055](https://github.com/coollabsio/coolify/issues/9055))
## [v4.6.0] - 2026-11-02
+1
View File
@@ -131,5 +131,6 @@ const NEEDS_TO_DISABLE_GZIP = [
];
const NEEDS_TO_DISABLE_STRIPPREFIX = [
'appwrite' => ['appwrite', 'appwrite-console', 'appwrite-realtime'],
'rybbit' => ['rybbit_backend'],
];
const SHARED_VARIABLE_TYPES = ['team', 'project', 'environment', 'server'];
+19 -16
View File
@@ -6,25 +6,12 @@
# port: 3002
services:
rybbit:
image: 'ghcr.io/rybbit-io/rybbit-client:v2.2.3'
environment:
- SERVICE_URL_RYBBIT_3002
- NODE_ENV=production
- 'NEXT_PUBLIC_BACKEND_URL=${SERVICE_URL_RYBBIT}'
- 'NEXT_PUBLIC_DISABLE_SIGNUP=${DISABLE_SIGNUP:-false}'
depends_on:
- rybbit_backend
healthcheck:
test: ["CMD-SHELL", "nc -z 127.0.0.1 3002"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
# rybbit_backend must stay before rybbit: the last SERVICE_URL_RYBBIT declaration sets SERVICE_URL_RYBBIT,
# and BASE_URL needs the root URL of the client, not the /api URL of the backend.
rybbit_backend:
image: 'ghcr.io/rybbit-io/rybbit-backend:v2.2.3'
environment:
- SERVICE_URL_RYBBIT_3001=/api
- NODE_ENV=production
- TRUST_PROXY=true
- 'BASE_URL=${SERVICE_URL_RYBBIT}'
@@ -55,6 +42,22 @@ services:
retries: 3
start_period: 10s
rybbit:
image: 'ghcr.io/rybbit-io/rybbit-client:v2.2.3'
environment:
- SERVICE_URL_RYBBIT_3002
- NODE_ENV=production
- 'NEXT_PUBLIC_BACKEND_URL=${SERVICE_URL_RYBBIT}'
- 'NEXT_PUBLIC_DISABLE_SIGNUP=${DISABLE_SIGNUP:-false}'
depends_on:
- rybbit_backend
healthcheck:
test: ["CMD-SHELL", "nc -z 127.0.0.1 3002"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
rybbit_postgres:
image: 'postgres:17.4'
environment:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -78,6 +78,28 @@ it('applies appwrite stripprefix prerequisite correctly', function () {
}
});
it('keeps the /api prefix for the rybbit backend', function () {
$application = new class
{
public $is_stripprefix_enabled = true;
public function save() {}
};
$query = Mockery::mock();
$query->shouldReceive('whereName')->with('rybbit_backend')->once()->andReturnSelf();
$query->shouldReceive('first')->once()->andReturn($application);
$service = Mockery::mock(Service::class)->makePartial();
$service->name = 'rybbit-clx1ab2cd3ef4g5hi6jk7l8m9n0o1p2q3';
$service->id = 1;
$service->shouldReceive('applications')->once()->andReturn($query);
applyServiceApplicationPrerequisites($service);
expect($application->is_stripprefix_enabled)->toBeFalse();
});
it('handles missing applications gracefully', function () {
$query = Mockery::mock();
$query->shouldReceive('whereName')