AutoCAR has two trusted endpoints: a local proxy client and a relay. Native mode
prefers AutoCAR v2 over QUIC/UDP and can use a separate native TLS/TCP listener.
Experimental, opt-in web-cover mode presents one normal website over H1/H2/TCP
and H3/UDP and can carry new TCP flows over H2 when UDP is unavailable. Choose one relay protocol
per endpoint and configure clients to match it. The defaults remain a native
relay and an auto client; installing v1.0.1 does not enable web-cover.
With a build containing init and --check (not the published v1.0.1 binary),
you can generate matching native server/client configuration without contacting
any network:
go build -trimpath -o autocar ./cmd/autocar
./autocar init --server relay.example.com:8443 --out ./autocar-config
./autocar server --config ./autocar-config/server/server.json --check
./autocar client --config ./autocar-config/client/client.json --checkReplace the relay address with yours. The output parent directory must exist;
the output directory must NOT exist. Existing paths, including empty directories
and symlinks, are refused. init is for new deployments, not credential rotation.
It generates a random 32-byte shared token and an ECDSA self-signed certificate;
--days controls certificate validity (default 365, range 1-1825). The default
certificate name comes from the relay host; --server-name selects an explicit
DNS/IP certificate identity, for example when connecting to an IP. No DNS lookup
is needed. Plan certificate renewal and trust-anchor redistribution separately.
Transfer only server/ to the relay and only client/ to the client through an
authenticated channel. The private key stays in server/. Both directories
contain the shared token and must remain private. Unix directories are 0700
and files 0600; Windows deployments must restrict their ACLs independently.
Assign ownership/read access to each host's runtime user. Generated .gitignore
files help prevent accidental Git adds; they are not a storage/access boundary.
If writing fails, the incomplete private directory is preserved for inspection;
do not deploy it or expect a retry to overwrite it.
Run server --config /path/to/server/server.json on the relay and
client --config /path/to/client/client.json locally. Config-relative paths make
the two directories independently movable. Both TCP and UDP listeners use the
numeric port in --server. No firewall, DNS, service installation or system
settings are changed. Low ports still require appropriate capability/port
mapping; don't use root simply to bind a low port. Local proxy listeners stay
loopback-only and the default destination policy is unchanged. For public-CA or
experimental web-cover deployments, use the manual configuration below instead.
go build -trimpath -o autocar ./cmd/autocar
sudo install -o root -g root -m 0755 autocar /usr/local/bin/autocar
# Once per host; use your distribution's equivalent if useradd is unavailable.
sudo useradd --system --user-group --home-dir /nonexistent \
--shell /usr/sbin/nologin autocar
sudo install -d -o autocar -g autocar -m 0700 /etc/autocar
sudo -u autocar /usr/local/bin/autocar token --out /etc/autocar/relay-token
sudo -u autocar /usr/local/bin/autocar cert \
--hosts relay.example.com,203.0.113.10 \
--cert /etc/autocar/server.crt \
--key /etc/autocar/server.keyKeep the private key only on the relay. Copy the token and trust anchor through
an authenticated channel. The relay process must be able to traverse the
credential directory and read its files: the private key must be a regular file
with mode exactly 0600, and the token must have no group/other permission bits
(autocar token creates it as 0600). Generate or install them as the runtime
user rather than leaving root-owned 0600 files for User=autocar. Do not reuse
the relay token as a local proxy password.
On each client, install the copied token with no group/other permission bits and make both token and CA certificate readable by that client's runtime user. The client paths below assume that ownership has already been set correctly.
External certificates are supported as long as their SAN covers the configured server name and the client trusts the issuing CA. AutoCAR performs normal chain, name and validity checks and has no certificate-verification bypass.
sudo -u autocar /usr/local/bin/autocar server \
--listen :8443 \
--tcp-listen :8443 \
--cert /etc/autocar/server.crt \
--key /etc/autocar/server.key \
--token-file /etc/autocar/relay-token \
--pacing adaptive \
--pacing-profile balancedThis manual example uses an unprivileged port. UDP and TCP may use the same port
number; open both protocols in the host/cloud firewall. --disable-tcp-fallback
removes the TCP listener; do this only after testing every client network.
The relay defaults to denying loopback, private, link-local, multicast,
unspecified and IANA special-purpose destinations plus SMTP submission ports.
Use --allow-private only when the relay is intentionally allowed to reach
RFC1918/ULA/CGNAT targets. It never opens loopback or link-local metadata
services. Add deployment-specific blocks with --deny-cidrs and
--deny-ports.
Resource controls include --max-connections, --max-client-connections,
--max-streams and --max-client-fallback-connections. --max-streams is one
global admission budget shared by the QUIC and TLS listeners; enabling fallback
does not double the configured stream capacity.
QUIC UDP associations have separate bounded controls:
--max-udp-sessionsglobally and--max-client-udp-sessionsper source;--max-udp-destinationsfor each association;--udp-receive-queuefor each bounded datagram work queue; and--udp-reassembly-ttl,--max-udp-reassembly-messages, and--max-udp-reassembly-bytesfor incomplete messages on each QUIC connection.
All UDP limits must be positive, and the per-source session limit cannot exceed the global UDP session limit. Start conservatively, watch memory/file descriptors and put host-level per-source UDP rate limits in front of a public relay.
Use web-cover only with a domain and site content you own or are authorized to serve. The static form is:
sudo -u autocar /usr/local/bin/autocar server \
--protocol web \
--listen :8443 \
--tcp-listen :8443 \
--cover-root /srv/autocar-cover \
--cert /etc/autocar/server.crt \
--key /etc/autocar/server.key \
--token-file /etc/autocar/relay-tokenFor a fixed authorized origin, replace --cover-root with, for example,
--cover-upstream https://origin.example.net. The two flags are mutually
exclusive and exactly one is required. The reverse proxy fixes the upstream
scheme and authority, rewrites Host, strips authorization and hop-by-hop
headers, and preserves the request path and query. Treat that origin as an
Internet-facing application; do not point it at metadata or control-plane
services.
--listen binds H3/UDP and --tcp-listen binds HTTPS/H1/H2. They must use the
same numeric port; if --tcp-listen is omitted it inherits --listen. Open both
TCP and UDP in the deployment firewall. --disable-tcp-fallback is invalid in
web mode because H2/TCP is part of the mode. --client-ca is also invalid: a
normal cover origin must complete TLS without requesting a client certificate.
The public TCP listener accepts TLS 1.2 and TLS 1.3 so ordinary website probes
can negotiate either version. Authenticated H2 tunnels remain TLS 1.3-only; a
TLS 1.2 CONNECT has its credential stripped and is handled only by the cover.
H3 remains TLS 1.3.
Web mode uses the same remote resolver and destination policy as native mode,
and shares one --max-streams admission budget across H2 and H3 tunnels. H3
CONNECT-UDP also uses --max-udp-sessions,
--max-client-udp-sessions, --max-udp-destinations, and
--udp-receive-queue. In web mode one UDP target consumes one request stream
and one UDP session; --max-udp-destinations bounds the numeric candidates
returned for that one target before a single endpoint is fixed. Native
reassembly flags do not apply because web datagrams are not fragmented. Native
connection/session flags do not substitute for ordinary public-web controls.
Apply host/container file-descriptor, memory, CPU, connection, request-rate,
and bandwidth limits appropriate to the exposed cover site.
Public cover compatibility is best checked with a real SAN-valid certificate, an ordinary site, TLS 1.2 and TLS 1.3 H1/H2 probes, and an H3 client. Include a TLS 1.2 CONNECT carrying a syntactically valid ticket in an owned-lab test and verify that it receives cover behavior without any destination dial. A private CA remains supported for closed deployments, but its handshake is not representative of a broadly trusted public website.
Pinned/private CA:
./autocar client \
--server relay.example.com:8443 \
--ca /etc/autocar/server.crt \
--token-file /etc/autocar/relay-token \
--transport auto \
--pacing adaptive \
--pacing-profile balancedFor a public CA, replace --ca with the explicit --system-roots. If the
connection address and certificate name differ, set --server-name.
auto gives the full QUIC attempt a budget and then uses TLS for new TCP flows.
--quic-attempt-timeout must be shorter than --open-timeout so fallback keeps
time to succeed. --fallback-cooldown prevents every new TCP connection from
paying the same UDP blackhole timeout. Use --transport=quic to require UDP or
--transport=tls to require TCP. TLS mode does not offer SOCKS5 UDP ASSOCIATE;
auto advertises UDP, but an association is still QUIC-only and fails when QUIC
is unavailable rather than crossing the TLS fallback.
./autocar client \
--server relay.example.com:8443 \
--system-roots \
--token-file /etc/autocar/relay-token \
--transport web-auto \
--h3-fingerprint chrome-2026-08 \
--quic-attempt-timeout 5s \
--open-timeout 15s \
--fallback-cooldown 30sUse --ca /path/to/ca.pem instead of --system-roots for a private trust
anchor. web-auto tries standard H3 CONNECT first and switches a new TCP flow
to standard H2 CONNECT after an H3 transport failure. During the cooldown, new
TCP flows use H2 without repeating the UDP wait. The configured cooldown is a
base with independent +/-20% jitter; after it, exactly one caller probes H3.
Use --transport=h3 or --transport=h2 to require one path during diagnosis.
chrome-2026-08 is the default H3 fingerprint. It uses the exactly pinned
github.com/apernet/quic-go fork for the complete client
QUIC/TLS handshake profile and a zero-length source CID. Use
--h3-fingerprint=native only as an interoperability or rollback diagnostic; it
disables ChromeParrot within the same web-H3 fork and does not select native
autocar/2. The profile is client-only and does not claim to reproduce server
behavior, H3 SETTINGS, CONNECT traffic or timing.
H3 and H2 use the same --server address, so --fallback-server is not valid
with web transports. Web transports reject --client-cert/--client-key and
--pacing=fixed-rate; native pacing metadata is reported as
not-applicable. Both web-auto and explicit h3 advertise SOCKS5 UDP using
H3 RFC 9298 CONNECT-UDP. Explicit h2 does not. The H3-to-H2 policy is for TCP
streams only: UDP fails when H3 is unavailable and never enters H2. Full
behavior and limits are in WEB_COVER.md.
Default local endpoints are loopback-only SOCKS5 127.0.0.1:1080 and HTTP
127.0.0.1:8080. Use socks5h:// when the relay should resolve names.
In source builds, closing the SOCKS5 UDP ASSOCIATE control connection also cancels that request's pending endpoint lookup or packet setup, releasing its local connection slot without waiting for the full dial timeout. A successful setup cancels its setup timer without terminating the established UDP session; the control connection must remain open for that session. Native QUIC's shared physical dial is client-owned and is not canceled just because one caller leaves. This does not change H3's existing cold-dial retry policy, graceful shutdown semantics or TCP CONNECT handling, and is not included in v1.0.1. Cancellation requires context-aware resolvers/dialers; custom implementations that ignore cancellation cannot be forcibly interrupted by the proxy.
For SOCKS5 TCP and HTTP CONNECT tunnels, --idle-timeout (default 5m)
measures inactivity across both directions: an active download or upload does
not need reverse-direction application traffic to stay open. A blocked write
still has its own timeout, so an unresponsive receiver cannot retain a tunnel
indefinitely. Ordinary HTTP forwarding also counts upload/download body
progress as activity, including small buffered responses. Stalled request or
response bodies and blocked writes remain bounded; header and keepalive
timeouts are unchanged.
Source builds also forward unknown-length HTTP response bodies and
text/event-stream events without waiting for the origin to finish. Fixed-size
non-streaming responses retain normal buffering. If copying an origin response
fails, the proxy aborts that response instead of emitting a successful final
chunk: HTTP/1.1 clients can detect truncation. Failure before buffered headers
are sent can instead appear as a connection error. Declared trailers are
forwarded only after the body completes successfully. This does not add HTTP
Upgrade support or change CONNECT tunnels, and is not included in v1.0.1.
The relay's separate --destination-write-timeout defaults to 5m; 0
also selects 5m, rather than disabling the limit. It bounds the completion
of each TCP destination write, split into chunks of at most 32 KiB. Each
successfully completed chunk gets a fresh budget for the next write. This is
not a kernel-level no-progress timer: a write can time out after making partial
progress, and that error is retained rather than silently retried.
This server setting applies to native QUIC/TLS and web H2/H3 TCP tunnels, not
UDP or ordinary cover requests. The write deadline is cleared after every
write, including failures; when no write is pending it does not count idle
time, change read deadlines, or limit total upload duration. A stalled target
therefore releases its stream slot within the pending write's timeout, even
in the H3 response-FIN/reset edge case described in WEB_COVER.md.
That is bounded cleanup, not a promise of immediate reset detection. Configure
it on the server as --destination-write-timeout=30s or JSON
"destination-write-timeout": "30s"; choose a longer value if individual
32 KiB writes can legitimately take longer. Negative durations are rejected by
normal startup and --check.
Source builds provide a separate client --h2-write-timeout for explicit h2
and the H2 fallback of web-auto. Its default is 30s; 0 selects that
default, and negative values are rejected. JSON uses
"h2-write-timeout": "30s". It is independent of --open-timeout, local proxy
idle timeouts and server destination-write timeouts, and does not change H3 or
native transport settings. This option is not in the v1.0.1 release.
This bounds pending HTTP/2 physical-connection writes, including control
frames, so a non-reading peer cannot indefinitely hold the shared writer lock
and prevent stream cleanup. No write is pending on a purely idle connection,
and successful writes clear their deadlines. It is a TLS write-call budget,
not a precise kernel-level byte-idleness timer: an exceptionally slow write
can time out despite partial network progress. Increase it if needed for such
links. The 30s default is an operational choice, not a measured universal
optimum. A TLS write timeout can terminate all streams on that connection;
new requests establish a fresh authenticated session. Normal per-stream
cancellation remains isolated. Stream close may wait for the pending write's
budget and cleanup; this is bounded recovery, not an immediate-close promise.
Before leaving a client running, verify a real authenticated relay path with the same connection flags:
./autocar doctor \
--server relay.example.com:8443 \
--ca /etc/autocar/server.crt \
--token-file /etc/autocar/relay-token \
--transport web-auto \
--target example.com:443 \
--jsonThis opens the target TCP connection through the tunnel; it does not merely
check a local listener. The result identifies the selected transport and
elapsed time. Native QUIC also reports sender/rate negotiation; web H2/H3
reports pacing as not-applicable. Exit status is 0 for success, 1 for a
failed live probe and 2 for invalid arguments or local configuration. Failed
JSON results retain a stable code and redacted description, with additive
diagnosis and hint fields for actionable troubleshooting. Human-mode failures
also use safe descriptions rather than echoing raw remote messages, arguments,
or local paths. Unknown failures remain explicitly unclassified; in particular,
a web cover response alone does not prove token rejection. Use --json on the
command line when automation needs JSON even if loading its config file fails.
Native auto-mode logs expose only stable fallback/recovery event and reason codes, never tokens, full targets, relay addresses or raw transport errors. Its event callbacks are asynchronous, serialized and backed by a bounded queue; consumers that fall behind should read the concurrency-safe snapshot as the authoritative latest state. The most recently completed native path is tracked separately from QUIC circuit health.
Builds containing the configuration-file change support --config for client,
server, and doctor; the published v1.0.1 binary does not. Existing CLI-only
commands are unchanged. Copy examples/client.json
and examples/server.json into your credential
directory and adjust addresses and filenames. These files contain references,
not secrets; keep the existing token and private-key permission requirements.
Do not overwrite an existing deployment config without reviewing/backing it up.
autocar client --config /etc/autocar/client.json
autocar doctor --config /etc/autocar/client.json --target example.com:443 --json
autocar server --config /etc/autocar/server.jsonA config is one JSON object (maximum 64 KiB). Its keys are the selected command's
long option names without --. CLI options override matching config entries,
including explicit empty strings and false; other entries keep their values.
Use JSON booleans, exact integers for numeric options, and strings for addresses,
paths and durations such as "15s". Duplicate/unknown keys, invalid types,
arrays, nested objects and trailing content are rejected, even if an invalid
entry is overridden on the command line. There are no comments, includes, shell
expansion, environment-variable expansion, or automatic reloads.
These commands also reject unexpected positional arguments instead of silently
ignoring them; use named options for every setting.
Relative credential/certificate/cover-root paths in JSON are resolved against
the config file's directory (not the process working directory). Paths supplied
on the CLI keep their existing working-directory semantics. To switch from a
configured private CA to system roots, explicitly clear the old setting:
--ca= --system-roots. Credentials themselves are never accepted inline in JSON;
token-file and proxy-password-file retain the existing environment fallback
when unset. Do not put passwords in addresses, URLs, or arbitrary string options.
The supplied client template intentionally contains only shared tunnel options,
so it can also be used by doctor. Client-only options such as socks, http,
and https are valid in a client-specific file but rejected by doctor; pass
them on the client command line if you want to reuse one connection config.
Server files are separate and cannot be used as client connection profiles.
Use a trusted, runtime-readable config and restart the process after editing it.
--help never reads config files or starts a network probe.
Before starting either endpoint, add --check to its normal client or server
command. It validates local option combinations and credential files without
binding a listener, resolving a hostname, connecting a peer, or modifying files.
Web-cover paths are checked locally but upstream health is not requested.
It can succeed even when the configured ports are occupied or the relay is
unreachable. It does not validate remote certificate identity, reachability,
firewalls, host-local port availability, or permissions needed to bind a port.
Address ports must be numeric for --check, avoiding service-name resolution;
normal startup continues to accept its existing service-name syntax.
--check is a command-line-only operation: a JSON check key is rejected even
if false or overridden, so a saved service configuration cannot silently turn
startup into a one-shot check. Remove the flag to actually run the service.
For routine diagnosis, use the same file with doctor, then temporarily require
--transport=tls (native) or --transport=h2 (web) to isolate the TCP path. A
successful TCP check does not validate UDP. Fallback/recovery applies to new
flows; applications must reconnect broken streams. AutoCAR does not replay
application requests or migrate already-open streams.
Use adaptive-balanced first. conservative reduces probing on shared or
shallow-buffer paths; aggressive should be enabled only after measuring both
throughput and queue delay. reno disables the AutoCAR pacing layer and leaves
the native upstream quic-go path as the baseline. Web H3 uses the separate pinned
fork and does not participate in native pacing negotiation.
Fixed-rate is appropriate only for a measured, provisioned link:
# Relay policy: finite limits in both directions and explicit client opt-in.
./autocar server [credential/policy flags] \
--pacing fixed-rate \
--max-upload-mbps 80 \
--max-download-mbps 250 \
--allow-client-rates
# Client request, no higher than its measured access link.
./autocar client [connection flags] \
--transport quic \
--pacing fixed-rate \
--upload-mbps 60 \
--download-mbps 200The protocol response reports the actual directional rates. These settings are
cooperative sender pacing, not an authorization boundary. Enforce tenant quotas
with tc, nftables or cloud policers. Fixed-rate negotiation exists only on
QUIC: explicit tls is rejected, while an auto TCP flow that falls back to TLS
is unpaced. Select quic when the rate behavior is required.
To require a client certificate, configure --client-ca on the relay and
--client-cert/--client-key on the client. The shared token remains a second
authorization factor. This is available only in native mode. Web-cover rejects
mTLS on both sides so that ordinary visitors can reach the cover site; its
per-request HMAC ticket remains mandatory for tunnel access.
An explicitly configured empty or malformed client CA file is an error, not a
request to turn off mTLS. Both normal startup and --check reject it.
CA, certificate and private-key files must be regular files no larger than
4 MiB each. Symlinks to valid regular files are allowed; named pipes and devices
are rejected before opening. Private keys still require Unix mode 0600.
Keep the configuration directory protected from untrusted writers: these input
checks are not a guarantee against hostile file replacement races.
SOCKS5 username/password and HTTP Basic are cleartext on the local hop. Keep those listeners on loopback or enable the local HTTPS proxy. A non-loopback plaintext listener requires an explicit override and should still be protected by a trusted private network/firewall.
When HTTP or HTTPS is enabled, --proxy-user must not contain : because HTTP
Basic uses it to separate the username and password. Startup and --check
reject this configuration. SOCKS-only usernames and passwords may contain :;
passwords containing : also remain valid for HTTP/HTTPS.
/etc/systemd/system/autocar.service:
[Unit]
Description=AutoCAR relay
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=autocar
Group=autocar
ExecStart=/usr/local/bin/autocar server --listen=:443 --tcp-listen=:443 --cert=/etc/autocar/server.crt --key=/etc/autocar/server.key --token-file=/etc/autocar/relay-token --pacing=adaptive --pacing-profile=balanced
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadOnlyPaths=/etc/autocar
LimitNOFILE=65536
[Install]
WantedBy=multi-user.targetThe two capability lines are needed only because this example binds UDP and TCP port 443 as an unprivileged user. Alternatively bind both listeners to a port at or above 1024, remove those lines and redirect/publish the port outside the process.
For web-cover, use the same hardening but select web protocol and an authorized cover source:
ExecStart=/usr/local/bin/autocar server --protocol=web --listen=:443 --tcp-listen=:443 --cover-root=/srv/autocar-cover --cert=/etc/autocar/server.crt --key=/etc/autocar/server.key --token-file=/etc/autocar/relay-tokenAdd the cover directory to ReadOnlyPaths (or an equivalent read-only bind) and
ensure User=autocar can traverse and read it.
With a post-v1.0.1 configuration-capable build, first manually copy
examples/server.json to /etc/autocar/server.json
and adjust its settings, as described in the reusable-configuration section.
Templates are not bundled or installed automatically by the release archive or
container image. After preparing that runtime-readable file, the native service
can use:
ExecStart=/usr/local/bin/autocar server --config=/etc/autocar/server.json --listen=:443The sample omits tcp-listen, so both protocols inherit the overridden port.
Keep the same unprivileged runtime user and hardening above. Restart=on-failure
restarts a failed process; transport recovery within a live process is separate.
docker build -t autocar:local .
# For rootful Docker on Linux, prepare a separate bind mount readable by the
# image's numeric runtime UID without weakening the key/token modes.
sudo install -d -o 65532 -g 65532 -m 0700 /etc/autocar-container
sudo install -o 65532 -g 65532 -m 0644 \
/etc/autocar/server.crt /etc/autocar-container/server.crt
sudo install -o 65532 -g 65532 -m 0600 \
/etc/autocar/server.key /etc/autocar-container/server.key
sudo install -o 65532 -g 65532 -m 0600 \
/etc/autocar/relay-token /etc/autocar-container/relay-token
docker run --rm \
-p 443:8443/udp -p 443:8443/tcp \
-v /etc/autocar-container:/etc/autocar:ro \
autocar:local server \
--listen=:8443 --tcp-listen=:8443 \
--cert=/etc/autocar/server.crt \
--key=/etc/autocar/server.key \
--token-file=/etc/autocar/relay-tokenFor a static web-cover container, mount the authorized site read-only and add the web flags while keeping both TCP and UDP port publications:
docker run --rm \
-p 443:8443/udp -p 443:8443/tcp \
-v /etc/autocar-container:/etc/autocar:ro \
-v /srv/autocar-cover:/srv/www:ro \
autocar:local server \
--protocol=web \
--listen=:8443 --tcp-listen=:8443 \
--cover-root=/srv/www \
--cert=/etc/autocar/server.crt \
--key=/etc/autocar/server.key \
--token-file=/etc/autocar/relay-tokenThe image runs as UID/GID 65532 and exposes 8443, so mounting the root-owned
systemd credential directory directly would normally be unreadable. Rootless or
user-namespace-remapped Docker uses a different host-ID mapping; prepare the
mount for the mapped runtime UID instead, and publish a non-privileged host port
unless the rootless runtime has been explicitly authorized to bind 443. The
image does not need host networking. Apply memory, CPU, PID and file-descriptor
limits appropriate to the configured connection limits.
Before production:
go test ./...
go test -race ./...
./autocar doctor [client flags] --target target.example:443 --json
./autocar bench-client [client flags] --target target.example:9000 --jsonAlso test TCP and UDP firewall rules separately, an invalid token, an invalid
certificate, UDP blackhole fallback, destination-policy rejection, and shutdown
under load. For native mode, test SOCKS5 UDP separately. For web mode, verify
ordinary H1/H2/H3 cover behavior and explicit h3, explicit h2, and
web-auto TCP paths. Verify CONNECT-UDP with an owned UDP fixture over h3 and
web-auto, including its 1,150-byte boundary and expected failure while H3 is
blocked. Run active probes only against loopback, isolated Docker networks, or
systems you own or are explicitly authorized to test; never scan unrelated
public endpoints.
A low-memory remote Linux host may run a non-release active smoke from an already loaded, matching image pair:
STEALTH_RELEASE_GATE=0 STEALTH_RUN_ROLE=remote-linux \
STEALTH_EXECUTION_HOST=198.51.100.10:22 \
STEALTH_AUTOCAR_IMAGE=autocar:smoke \
STEALTH_LAB_IMAGE=autocar-stealth-lab:smoke \
./scripts/stealth-active.shBoth image variables are mandatory together, and the harness must be launched
from a direct session to the host named by STEALTH_EXECUTION_HOST and from a
valid AutoCAR Git checkout so it can record source-state stability. This
avoids compiling on that host but is smoke evidence only: the optional research
gate rejects prebuilt images because it must build from the exact frozen Git archive.
Remote manifests also record the ED25519 host-key fingerprint derived from the
machine's /etc/ssh/ssh_host_ed25519_key.pub; release evidence must match the
endpoint and fingerprint frozen in the preregistration. See
STEALTH-BENCHMARK.md for the research evidence contract,
and RELEASING.md for ordinary release quality checks.
autocar/2 and web-cover do not provide third-party proxy or AutoCAR v1 compatibility.
The shared web-H3 QUIC implementation does not change that protocol boundary.
For a rolling breaking upgrade, start the new relay on a second UDP/TCP port,
move clients, verify each selected transport independently, and then retire the
old endpoint. There is no silent protocol-family downgrade.
The version number v1.0.0 is not the retired AutoCAR v1 wire protocol. Both
v1.0.0 and v1.0.1 native endpoints use autocar/2; web-cover is new in v1.0.1
and requires matching web-capable endpoints. Keep the existing native
configuration when a feature change is not intended.
- Download the archive for the host architecture and verify its entry in the
release's
SHA256SUMS. Recordautocar versionand retain the previous executable, service definition, token, certificate, and configuration in a protected backup. Do not put secrets in a release report. - Test v1.0.1 on a separate, explicitly permitted TCP/UDP port with the same
certificate trust and destination policy. For a native rolling upgrade,
test the old client against the new relay and the new client against the
old relay for every transport actually used:
quic,tls,auto, and SOCKS5 UDP where required. A successfuldoctoronly checks a TCP open; also exercise application traffic and UDP separately. - Replace one endpoint at a time, restart its managed service, and rerun those checks before proceeding. Restarting an endpoint disconnects its current streams; drain or schedule an interruption where needed.
- To try web-cover, keep the native endpoint available on its original port
and bring up a separate v1.0.1
--protocol webendpoint. Move only opted-in clients toweb-auto,h3, orh2. Check cover responses, authenticated TCP, H3 CONNECT-UDP's 1,150-byte boundary, invalid credentials and the H3-to-H2 new-flow fallback before wider use. Web mode does not support mTLS or H2 UDP. - For a native rollback, restore the recorded v1.0.0 executable and native service configuration, restart, and repeat the same path checks. For a web rollback, move clients back to the retained native endpoint/configuration first; a v1.0.0 executable cannot consume web flags or speak the web protocol. Do not overwrite working keys or tokens merely to roll back a binary.
These are deployment acceptance steps, not a claim that every operating system, network, or application has been tested. Cross-compiled release archives alone are not native runtime validation for their target platform.