← All migration guides

Competitor migration guide

Migrate from Pingora to Webship without a blind cutover.

Replace a custom Pingora edge service with declarative Webship routes where standard TLS, proxying, health, policy, and observability are sufficient.

Applies to Webship 1.1.0Rust + YAML

Define the migration boundary before changing traffic.

Start by moving only the behavior Webship can reproduce and validate. Leave application authentication, service discovery, scripts, and specialized cache rules on the existing origin until their replacements pass production-like tests.

Translate the smallest production path first.

The source fragment identifies the migration concept; the Webship fragment shows the target shape. Replace example domains, addresses, certificates, limits, and health paths with values validated for your environment.

Representative Pingora configuration
let mut server = Server::new(None)?;
server.bootstrap();
let mut proxy = http_proxy_service(
    &server.configuration, MyProxy::new("127.0.0.1:8080"),
);
proxy.add_tcp("0.0.0.0:443");
server.add_service(proxy);
server.run_forever();
Equivalent Webship TOML
listen = "0.0.0.0:443"
workers = 4

[reverse_proxy]
enabled = true
connect_timeout_ms = 2000
max_retries = 0

[reverse_proxy.protocols]
h1 = true
h2 = true
h3 = true

[reverse_proxy.tls]
cert = "/etc/letsencrypt/live/app.example.com/fullchain.pem"
key = "/etc/letsencrypt/live/app.example.com/privkey.pem"

[[reverse_proxy.routes]]
domain = "app.example.com"
path_prefix = "/"
upstreams = ["127.0.0.1:8080", "127.0.0.1:8081"]
load_balancing = "weighted-peak-ewma"

[[reverse_proxy.upstreams]]
address = "127.0.0.1:8080"
protocol = "http1"
health_check_path = "/health"
health_check_interval_ms = 5000
health_check_timeout_ms = 1000

[[reverse_proxy.upstreams]]
address = "127.0.0.1:8081"
protocol = "http1"
health_check_path = "/health"
health_check_interval_ms = 5000
health_check_timeout_ms = 1000

[[reverse_proxy.policies]]
name = "default"
hosts = []
path_prefixes = ["/"]
methods = []
max_body_bytes = 1048576
total_timeout_ms = 30000

Map concepts, not syntax.

Technical directives do not always match one-to-one. Use this table to locate the equivalent Webship configuration area, then validate the effective configuration and runtime behavior.

Current concept or directiveWebship configuration target
listener / frontendlisten + [reverse_proxy.protocols]
host + path matcher[[reverse_proxy.routes]]
backend / cluster / service[[reverse_proxy.upstreams]]
health probe[[reverse_proxy.upstreams]].health_check_*
request limits and timeouts[[reverse_proxy.policies]]
certificate and private key[reverse_proxy.tls] / [[sites]] cert + key

Use a reversible five-step cutover.

Keep the old listener ready until Webship has passed correctness, capacity, security, observability, and rollback gates on representative traffic.

  1. 1

    Inventory observable behavior

    Record listeners, domains, routes, upstreams, certificates, rewrites, authentication, cache rules, health probes, limits, and operational integrations.

  2. 2

    Translate one boundary

    Move one host or route into strict TOML. Retain vendor-specific modules and application logic behind Webship until separate replacements are proven.

  3. 3

    Validate offline and locally

    Run --check-config and --print-effective-config, inspect the redacted result, probe health locally, and exercise TLS over both TCP and UDP when HTTP/3 is enabled.

  4. 4

    Canary real traffic

    Send a small, observable traffic slice to Webship. Compare status codes, headers, bodies, latency, upstream health, cache behavior, logs, and security decisions.

  5. 5

    Promote with rollback ready

    Increase traffic in measured stages. Keep the previous target healthy and immediately routable until the agreed observation window and load gates pass.

Validate first. Roll back by routing, not by editing live.

Validate the candidate file, inspect the redacted effective configuration, and probe the private listener before changing traffic. Preserve the old binary, configuration, listener, and DNS or load-balancer target until the observation window closes.

/usr/local/bin/webship --check-config --config /etc/webship/production.toml
/usr/local/bin/webship --print-effective-config --config /etc/webship/production.toml
curl --http3-only --insecure https://127.0.0.1:443/health