This commit is contained in:
Timothy Jaeryang Baek committed 2026-11-02 08:27:16 +09:00
1 parent b1fdd9ea1d
commit 200b7ee445
7 files changed
+51 -10

No files matched your search

+14
View File
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [0.15.2] - 2026-11-02
### Added
- Added `OPEN_TERMINAL_BROWSER_NO_SANDBOX=true` for deployments where Chromium cannot start with its sandbox enabled. The same setting applies to Browser tabs and Chromium opened from the Linux Desktop in the Docker image. Restart or redeploy Open Terminal after changing it. This setting turns off Chromium's built-in sandbox protection.
### Fixed
- Chrome startup failures on Linux and Mac now show the actual error, such as a locked browser profile or an unavailable sandbox, instead of the generic message asking you to check the installation, user, and sandbox support. The error is also saved in the server logs.
### Security
- Chromium's sandbox now stays enabled by default in Docker. Previously, Open Terminal automatically disabled it when it detected Docker. Existing deployments that cannot run sandboxed Chromium must now explicitly set `OPEN_TERMINAL_BROWSER_NO_SANDBOX=true` to keep launching the browser.
## [0.15.1] - 2026-11-02
### Added
+6
View File
@@ -66,6 +66,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
xauth xdotool xclip scrot libreoffice libreoffice-gtk3 \
&& rm -rf /var/lib/apt/lists/*
# Debian's launcher resets CHROMIUM_FLAGS before reading this directory.
RUN printf '%s\n' \
'case "${OPEN_TERMINAL_BROWSER_NO_SANDBOX:-false}" in' \
' [tT][rR][uU][eE]|1|[yY][eE][sS]) export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --no-sandbox" ;;' \
'esac' > /etc/chromium.d/open-terminal
COPY . .
# Create a capability-bearing Python copy for the server process only.
# The system python3 stays clean so user-spawned Python processes remain
+6
View File
@@ -234,6 +234,12 @@ and advertise them as disabled in `/api/config`. Values `false`, `0`, and `no`
(case-insensitive) disable the feature. Restart the server after changing these settings.
Desktop support still requires its platform dependencies to be available.
Chromium's sandbox is enabled by default, including in Docker. For a deployment
that cannot support it, set `OPEN_TERMINAL_BROWSER_NO_SANDBOX=true` and restart the
server. This applies to both managed Browser tabs and Chromium launched from the
Linux Desktop in the Docker image. It disables Chromium's sandbox; the container's isolation remains
unchanged. Values `true`, `1`, and `yes` (case-insensitive) enable this override.
> [!TIP]
> Use the system config at `/etc/open-terminal/config.toml` to set site-wide defaults for host and port, and the user config for personal settings like the API key — this keeps the key out of `ps` / `htop`.
+17 -8
View File
@@ -17,7 +17,7 @@ import sys
import websockets
from fastapi import WebSocket, WebSocketDisconnect
from open_terminal.env import sanitized_environ
from open_terminal.env import BROWSER_NO_SANDBOX, sanitized_environ
from .rewrite import target_url
log = logging.getLogger(__name__)
@@ -104,8 +104,15 @@ class Host:
self.sequence = 0
self.pending = {}
self.handlers = {}
self.stderr = b""
self.stderr_reader = asyncio.create_task(self.read_stderr())
self.reader = asyncio.create_task(self.read())
async def read_stderr(self):
if self.process.stderr is not None:
while chunk := await self.process.stderr.read(4096):
self.stderr = (self.stderr + chunk)[-4096:]
async def read(self):
try:
while True:
@@ -171,6 +178,8 @@ class Host:
await self.process.wait()
self.reader.cancel()
await asyncio.gather(self.reader, return_exceptions=True)
with contextlib.suppress(TimeoutError):
await asyncio.wait_for(self.stderr_reader, 1)
if self.channel:
await self.channel.close()
if self.display:
@@ -243,13 +252,13 @@ async def get_host(session):
"--no-default-browser-check",
"--disable-dev-shm-usage",
]
if BROWSER_NO_SANDBOX:
args.append("--no-sandbox")
if os.name == "nt":
host = await windows_host(args, profile, session.fs.home)
hosts[key] = host
return host
args.append("--remote-debugging-pipe")
if Path("/.dockerenv").exists():
args.append("--no-sandbox")
display = None
if all(
shutil.which(name) for name in ("Xtigervnc", "xauth", "xrandr", "xdotool")
@@ -302,7 +311,7 @@ async def get_host(session):
*command,
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL,
stderr=asyncio.subprocess.PIPE,
limit=16 * 1024 * 1024,
**kwargs,
)
@@ -313,11 +322,11 @@ async def get_host(session):
host = Host(process, display)
try:
await host.send("Browser.getVersion")
except Exception:
except Exception as exc:
await host.close()
raise RuntimeError(
"Chrome could not start. Check its installation, OS user, and sandbox support."
)
detail = host.stderr.decode(errors="replace").strip() or str(exc)
log.warning("Chrome startup failed: %s", detail)
raise RuntimeError(f"Chrome could not start: {detail}") from exc
hosts[key] = host
return host
+3 -1
View File
@@ -24,7 +24,7 @@ from fastapi.responses import Response
from pydantic import BaseModel, Field, model_validator
from open_terminal.dependencies import get_filesystem, matches_api_key, verify_api_key
from open_terminal.env import sanitized_environ
from open_terminal.env import BROWSER_NO_SANDBOX, sanitized_environ
from open_terminal.utils.fs import UserFS
router = APIRouter(prefix="/desktop", tags=["desktop"])
@@ -67,6 +67,8 @@ class Desktop:
"XDG_RUNTIME_DIR": str(self.runtime),
"XAUTHORITY": str(self.runtime / "Xauthority"),
}
if BROWSER_NO_SANDBOX:
self.env["OPEN_TERMINAL_BROWSER_NO_SANDBOX"] = "true"
async def spawn(self, *command, **kwargs):
if self.fs.username:
+4
View File
@@ -144,6 +144,10 @@ ENABLE_BROWSER = os.environ.get(
str(config.get("enable_browser", True)),
).lower() not in ("false", "0", "no")
BROWSER_NO_SANDBOX = os.environ.get(
"OPEN_TERMINAL_BROWSER_NO_SANDBOX", "false"
).lower() in ("true", "1", "yes")
ENABLE_DESKTOP = os.environ.get(
"OPEN_TERMINAL_ENABLE_DESKTOP",
str(config.get("enable_desktop", True)),
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "open-terminal"
version = "0.15.1"
version = "0.15.2"
description = "A remote computer API."
license = "MIT"
readme = "README.md"