Info
Content

Reproxy

https://reproxy.io/

Reproxy это простой edge HTTP(s) сервер / reverse proxy поддерживающий множество провайдеров (docker, static, file, consul catalog). Один или более провайдеров предоставляют информацию о запрашиваемых серверах, запрашиваемых URL, конечных URL и health check URL. Он распрастраняется в виде одиночного бинарного файла или как docker image

  • Automatic SSL termination with Let’s Encrypt
  • Support of user-provided SSL certificates
  • Simple but flexible proxy rules
  • Static, command-line proxy rules provider
  • Dynamic, file-based proxy rules provider
  • Docker provider with an automatic discovery
  • Consul Catalog provider with discovery by service tags
  • Support of multiple (virtual) hosts
  • Optional traffic compression
  • User-defined size limits and timeouts
  • Single binary distribution
  • Docker container distribution
  • Built-in static assets server with optional “SPA friendly” mode
  • Support for redirect rules
  • Optional limiter for the overall activity as well as for user’s activity
  • Live health check and fail-over/load-balancing
  • Management server with routes info and prometheus metrics
  • Plugins support via RPC to implement custom functionality
  • Optional logging with both Apache Log Format, and simplified stdout reports.

Сервер (host) может быть указан как FQDN (s.example.com, * (catch all)) или как регулярное выражение. Приоритетнее будет полное совпадение, так, если у нас будет два правила с серверами example.com и example\.(com|org), то запрос example.com/some/url уйдет на первый сервер. Запрашиваемый URL тоже может быть указан как регулярное выражение, например ^api/(.*), а конечный URL может содержать группы из регулярного выражения запрашиваемого URL, например http://d.example.com:8080/$1. В итоге http://s.example.com/api/something?foo=bar будет отпроксирован в http://d.example.com:8080/something?foo=bar

Для удобства, запросы с / на конце и без regex группы автоматически расширяются до /(.*), а конечные URL в таком случае расширяются до /$1. То есть /api/ -> http://localhost/service будет переведен в ^/api/(.*) -> http://localhost/service/$1

Поддерживается как HTTP так и HTTPS. Для HTTPS могут быть использованы как статичные (пользовательские) сертификаты, так и автоматически выпущенные через ACME (Let's Encrypt). Опциональный сервер ассетов может быть использован для раздачи статических файлов. Чтобы запустить Reproxy нужен как минимум один провайдер. Остальные параметры опциональны и имеют разумные дефолтные значения

Примеры:

  • with a static provider: reproxy --static.enabled --static.rule="example.com/api/(.*),https://api.example.com/$1"
  • with an automatic docker discovery: reproxy --docker.enabled --docker.auto
  • as a docker container: docker up -p 80:8080 umputun/reproxy --docker.enabled --docker.auto
  • with automatic SSL: docker up -p 80:8080 -p 443:8443 umputun/reproxy --docker.enabled --docker.auto --ssl.type=auto --ssl.fqdn=example.com

Install

Reproxy распространяется как маленький сдержанный бинарный файл, а также как docker image. И бинарь и докер имадж поддерживают множество архитектур и множество ОС, также есть deb/rpm пакеты

Providers

Правила проксирования предоставляются провайдерами. Сейчас в приложение включены - file, docker, static и consul-catalog. Каждый провайдер может предоставлять множество правил роутинга и для проксируемых запросов и для раздачи статики (assets). Пользователь может указывать множество провайдеров одновременно

Static provider

Это простейший провайдер который указывает правила прямо в командной строке (или через переменные окружения). Поддерживается возможность указания множества правил. Каждое правило это 3 или 4 разделенных запятой элемента server,sourceurl,destination[,ping-url]. Например:

  • *,^/api/(.*),https://api.example.com/$1 - proxy all request to any host/server with /api prefix to https://api.example.com
  • example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping - proxy all requests to example.com and with /foo/bar url to https://api.example.com/zzz and it sees https://api.example.com/ping for the health check

Последний (четвертый) элемент определяет опциональный ping url

File provider

Этот провайдер использует yaml файл с правилами роутинга

reproxy --file.enabled --file.name=config.yml

Пример конфига:

default: # the same as * (catch-all) server
  - { route: "^/api/svc1/(.*)", dest: "http://127.0.0.1:8080/blah1/$1" }
  - {
      route: "/api/svc3/xyz",
      dest: "http://127.0.0.3:8080/blah3/xyz",
      ping: "http://127.0.0.3:8080/ping",
    }
srv.example.com:
  - { route: "^/api/svc2/(.*)", dest: "http://127.0.0.2:8080/blah2/$1/abc" }
  - { route: "^/web/", dest: "/var/www", "assets": true }

Изменения в файле подтягиваются автоматически

Docker provider

https://reproxy.io/#docker-provider

Consul Catalog provider

https://reproxy.io/#consul-catalog-provider

Compose-specific details

https://reproxy.io/#compose-specific-details

SSL support

Режим работы по SSL может быть выставлен в auto (ACME/LE сертификаты), static (существующие сертификаты) или none (по умолчанию none). Если стоит auto, то сертификаты будут выпущены автоматически для всех найденных server names. Пользователь может изменить это поведение явно указав нужные домены в --ssl.fqdn

Headers

Reproxy позволяет удалять входящие заголовки с помощью опции --drop-header которая может быть указана множество раз. Этот параметр может быть полезен чтобы быть уверенным что некоторые заголовки установлены внутренними сервисами, а не подсунуты пользователем. Например, если какой-то из сервисов ответственный за аутентификацию подставляет заголовки X-Auth-User и X-Auth-Token, то может быть полезно удалять такие заголовки у входящих от пользователей запросов, это можно делать так --drop-header=X-Auth-User --drop-header=X-Auth-Token или через переменную окружения DROP_HEADERS=X-Auth-User,X-Auth-Token

Также доступна противополжная функция подстановки заголовков в исходящие ответы. Это можно делать с помощью параметра --header который можно указывать много раз или через переменную HEADER
Пример того как это выглядит в docker-compose:

environment:
      - HEADER=
          X-Frame-Options:SAMEORIGIN,
          X-XSS-Protection:1; mode=block;,
          Content-Security-Policy:default-src 'self'; style-src 'self' 'unsafe-inline';

Logging

По умолчанию запросы не логируются, но это поведение можно изменить с помощью опции --logger.enabled. Лог ротируется автоматически и имеет Apache Combined Log Format

С помощью опции --logger.stdout можно сказать Reproxy выводить краткий лог зарпосов в stdout (это не влияет на логирование в файл, а просто добавляет краткий лог в stdout)

Assets Server

Пользователь может включить сервер ассетов для обслуживания запросов к статике (по умолчанию он выключен). Пока установлен параметр --assets.location он будет пытаться обработать запросы по пути assets.root как запросы к статике (assets.root - часть урла, assets.location - путь до файлов). Сервер ассетов может быть использован без каких-либо провайдеров, в этом режиме Reproxy работает как простой web-server для раздачи статического контента. Также есть режим SPA который можно включить параметром --assets.spa, в таком случае каждый запрос к ненайденному файлу будет перенаправляться на index.html

В дополнение к основному серверу статики поддерживается множество кастомных. Каждый провайдер имеет собственный вариант указания его, а некоторые провайдеры его и вовсе не имеют

  • static provider - if source element prefixed by assets: or spa: it will be treated as file-server. For example *,assets:/web,/var/www, will serve all /web/* request with a file server on top of /var/www directory
  • file provider - setting optional fields assets: true or spa: true
  • docker provider - reproxy.assets=web-root:location, i.e. reproxy.assets=/web:/var/www. Switching to spa mode done by setting reproxy.spa to yes or true

Caching

Сервер ассетов имеет контроль кэширования, который задается через опцию --assets.cache=<duration>. 0s в этой опции отключит кэширование. <duration> это последовательность десятичных чисел, которые могут дробными и имеют суффикс обозначающий величину, например “300ms”, “1.5h” или “2h45m”. Валидные суффиксы: “ns”, “us” (or “µs”), “ms”, “s”, “m”, “h” и “d”

Есть два варианта указания длительности кэширования:

  • A single value for all static assets. This is as simple as --assets.cache=48h
  • Custom duration for different mime types. It should include two parts - the default value and the pairs of mime:duration. In command line this looks like multiple --assets.cache options, i.e. --assets.cache=48h --assets.cache=text/html:24h --assets.cache=image/png:2h. Environment values should be comma-separated, i.e. ASSETS_CACHE=48h,text/html:24h,image/png:2h

Кастомная страница для ответа 404 может быть задана через опцию --assets.404=<path>. Этот путь указывается относительно пути assets root

Using reproxy as a base image

https://reproxy.io/#using-reproxy-as-a-base-image

SPA-friendly mode

Некоторые SPA приложения полагаются на прокси для обработки 404 особым способом - перенаправляя на /index.html. Это похоже на nginx'овую директиву try_files $uri $uri/ ... и предположительно эта функция что-то важное для современных web приложений

По умолчанию в Reproxy эта функция выключена, но может быть включена с помощью --assets.spa или ASSETS_SPA=true

Redirects

По умолчанию Reproxy пробует destination как proxy location, то есть делает внутренний http запрос и возвращает ответ клиенту Однако это поведение можно изменить префиксируя destination url с помощью @code. Таким образом если указать @301 https://example.com/something, то получим редирект на Location: https://example.com/something
Поддерживаемые коды:

  • @301, @perm - permanent redirect
  • @302, @temp, @tmp - temporary redirect

More options

  • --gzip enables gzip compression for responses.
  • --max=N allows to set the maximum size of request (default 64k). Setting it to 0 disables the size check.
  • --timeout.* various timeouts for both server and proxy transport. See timeout section in All Application Options. A zero or negative value means there will be no timeout.

Default ports

Чтобы избежать необходимости прописывать кастомные параметры/окружения, дефолтный --listen - динамичный, он пытается быть разумным и полезным для типичных кейсов:

  • If anything set by users to --listen all the logic below ignored and host:port passed in and used directly.
  • If nothing set by users to --listen and reproxy runs outside of the docker container, the default is 127.0.0.1:80 for http mode (ssl.type=none) and 127.0.0.1:443 for ssl mode (ssl.type=auto or ssl.type=static).
  • If nothing set by users to --listen and reproxy runs inside the docker, the default is 0.0.0.0:8080 for http mode, and 0.0.0.0:8443 for ssl mode.

Another default set in the similar dynamic way is --ssl.http-port. For run inside of the docker container it set to 8080 and without to 80.

Ping, health checks and fail-over

Reproxy предоставляет два эндпоинта для этих целей:

  • /ping responds with pong and indicates what reproxy up and running
  • /health returns 200 OK status if all destination servers responded to their ping request with 200 or 417 Expectation Failed if any of servers responded with non-200 code. It also returns json body with details about passed/failed services.

В дополнение к эндпоинтам выше, Reproxy поддерживает проверки в реальном времени. В таком случае (если они включены) каждый конечный url периодически проверяется на ping ответ и в случае ошибки исключается из роутинга. Это дает возможность возвращать множество идентичных конечных url из одного или множества провайдеров, и будут выбраны только прошедшие проверки. Если множество подходящих было обнаружено и проверки были пройдены - только один будет использоваться в соответствии со стратегией lb-type (по умолчанию случайный выбор)

Чтобы включить проверки в реальном времени, пользователю нужно указать --health-check.enabled (или через переменную HEALTH_CHECK_ENABLED=true). Для кастомизации интервала - --health-check.interval=

Management API

Опционально с помощью флага --mgmt.enabled можно включить два эндпоинта которые будут доступны на mgmt.listen:

  • GET /routes - list of all discovered routes
  • GET /metrics - returns prometheus metrics (http_requests_total, response_status and http_response_time_seconds)

Errors reporting

Reproxy вернет 502 (Bad Gateway) в случае если запрос не матчится ни на один имеющийся роут или ассет. В случае неожиданных внутренних ошибок он вернет 500. По умолчанию он рендерит простейшую текстовую версию страницы ошибки - "Server error". Настройка --error.enabled включит дефолтную html страницу, а с помощью --error.template пользователь может установить любой кастомный html шаблон для ошибок. В таком темплейте будут доступны две переменные {{.ErrCode}} и {{.ErrMessage}}
Например шаблон oh my! {{.ErrCode}} - {{.ErrMessage}} будет отрендерен в oh my! 502 - Bad Gateway

Throttling

Reproxy позволяет задать ограничение в max req/sec как для всей системы, так и для пользователей. Значение 0 воспринимается как - неограничено

Ограничение на пользовательскую активность (запросы) распространяется как на сматченные, так и несматченные роуты. Все несматченные роуты рассматриваются как "single destination group" и ограничиваются в rate*3. Это значит что если указано --throttle.user=10 то конечный пользователь сможет делать вплоть до 30 запросов в секунду на какие-то статические ассеты или несматченные роуты. Для сматченных роутов это ограничение выставляется per destination, таким образом запросы проксируемые на s1.example.com/api будут ограничены 10r/s, а запросы проксируемые на s2.example.com будут ограничены другими 10r/s

Basic auth

Reproxy поддерживает Basic Auth для всех запросов. Это полезно для защиты эндпоинтов которые находятся в разработке или тестировании до запуска их в публичный доступ. Эта функция выключена по умолчанию и не достаточно гранулярна для настройки ее на каждый роут отдельно
Таким образом включенный Basic Auth будет влиять на все запросы

Чтобы включить Basic Auth для всех запросов пользователю нужно указать типичный htpasswd файл в опции --basic-htpasswd=<file location> или с помощью переменной BASIC_HTPASSWD=<file location>

Reproxy ожидает htpasswd файл в следующем формате:

username1:bcrypt(password2)
username2:bcrypt(password2)
...

Его можно сгенерировать с помощью htpasswd -nbB

Plugins support

https://reproxy.io/#plugins-support

Container security

https://reproxy.io/#container-security

Options

Каждая опция может быть указана двумя способами: опция командной строки и переменная окружения. Некоторые cli опции имеют короткую форму, как -l localhost:8080 и --listen localhost:8080. Имя соответствующей переменной окружения указано в конце описания каждой опции

Все опции описывающие размеры поддерживают суффикс величины 10K (or 10k) for kilobytes, 16M (or 16m) for megabytes, 10G (or 10g) for gigabytes. Отсутствие суффикса воспринимается как байты

Некоторые опции могут быть указаны несколько раз, в таком случае пользователь может несколько раз указать cli опцию, либо через запятую перечислить значения в переменной окружения. Например опция --ssl.fqdn одна из таких и может быть указана как --ssl.fqdn=a1.example.com --ssl.fqdn=a2.example.com или как переменная SSL_ACME_FQDN=a1.example.com,a2.example.com

Ниже список всех таких опций:

  • ssl.fqdn (SSL_ACME_FQDN)
  • assets.cache (ASSETS_CACHE)
  • docker.exclude (DOCKER_EXCLUDE)
  • static.rule ($STATIC_RULES)
  • header ($HEADER)
  • drop-header ($DROP_HEADERS)

All Application Options

  -l, --listen=                     listen on host:port (default: 0.0.0.0:8080/8443 under docker, 127.0.0.1:80/443 without) [$LISTEN]
  -m, --max=                        max request size (default: 64K) [$MAX_SIZE]
  -g, --gzip                        enable gz compression [$GZIP]
  -x, --header=                     outgoing proxy headers to add [$HEADER]
      --drop-header=                incoming headers to drop [$DROP_HEADERS]
      --basic-htpasswd=             htpasswd file for basic auth [$BASIC_HTPASSWD]      
      --lb-type=[random|failover]   load balancer type (default: random) [$LB_TYPE]
      --signature                   enable reproxy signature headers [$SIGNATURE]
      --dbg                         debug mode [$DEBUG]

ssl:
      --ssl.type=[none|static|auto] ssl (auto) support (default: none) [$SSL_TYPE]
      --ssl.cert=                   path to cert.pem file [$SSL_CERT]
      --ssl.key=                    path to key.pem file [$SSL_KEY]
      --ssl.acme-location=          dir where certificates will be stored by autocert manager (default: ./var/acme) [$SSL_ACME_LOCATION]
      --ssl.acme-email=             admin email for certificate notifications [$SSL_ACME_EMAIL]
      --ssl.http-port=              http port for redirect to https and acme challenge test (default: 8080 under docker, 80 without) [$SSL_HTTP_PORT]
      --ssl.fqdn=                   FQDN(s) for ACME certificates [$SSL_ACME_FQDN]

assets:
  -a, --assets.location=            assets location [$ASSETS_LOCATION]
      --assets.root=                assets web root (default: /) [$ASSETS_ROOT]
      --assets.spa                  spa treatment for assets [$ASSETS_SPA]
      --assets.cache=               cache duration for assets [$ASSETS_CACHE]
      --assets.not-found=           path to file to serve on 404, relative to location [$ASSETS_NOT_FOUND]

logger:
      --logger.stdout               enable stdout logging [$LOGGER_STDOUT]
      --logger.enabled              enable access and error rotated logs [$LOGGER_ENABLED]
      --logger.file=                location of access log (default: access.log) [$LOGGER_FILE]
      --logger.max-size=            maximum size before it gets rotated (default: 100M) [$LOGGER_MAX_SIZE]
      --logger.max-backups=         maximum number of old log files to retain (default: 10) [$LOGGER_MAX_BACKUPS]

docker:
      --docker.enabled              enable docker provider [$DOCKER_ENABLED]
      --docker.host=                docker host (default: unix:///var/run/docker.sock) [$DOCKER_HOST]
      --docker.network=             docker network [$DOCKER_NETWORK]
      --docker.exclude=             excluded containers [$DOCKER_EXCLUDE]
      --docker.auto                 enable automatic routing (without labels) [$DOCKER_AUTO]
      --docker.prefix=              prefix for docker source routes [$DOCKER_PREFIX]

consul-catalog:
      --consul-catalog.enabled      enable consul catalog provider [$CONSUL_CATALOG_ENABLED]
      --consul-catalog.address=     consul address (default: http://127.0.0.1:8500) [$CONSUL_CATALOG_ADDRESS]
      --consul-catalog.interval=    consul catalog check interval (default: 1s) [$CONSUL_CATALOG_INTERVAL]

file:
      --file.enabled                enable file provider [$FILE_ENABLED]
      --file.name=                  file name (default: reproxy.yml) [$FILE_NAME]
      --file.interval=              file check interval (default: 3s) [$FILE_INTERVAL]
      --file.delay=                 file event delay (default: 500ms) [$FILE_DELAY]

static:
      --static.enabled              enable static provider [$STATIC_ENABLED]
      --static.rule=                routing rules [$STATIC_RULES]

timeout:
      --timeout.read-header=        read header server timeout (default: 5s) [$TIMEOUT_READ_HEADER]
      --timeout.write=              write server timeout (default: 30s) [$TIMEOUT_WRITE]
      --timeout.idle=               idle server timeout (default: 30s) [$TIMEOUT_IDLE]
      --timeout.dial=               dial transport timeout (default: 30s) [$TIMEOUT_DIAL]
      --timeout.keep-alive=         keep-alive transport timeout (default: 30s) [$TIMEOUT_KEEP_ALIVE]
      --timeout.resp-header=        response header transport timeout (default: 5s) [$TIMEOUT_RESP_HEADER]
      --timeout.idle-conn=          idle connection transport timeout (default: 90s) [$TIMEOUT_IDLE_CONN]
      --timeout.tls=                TLS hanshake transport timeout (default: 10s) [$TIMEOUT_TLS]
      --timeout.continue=           expect continue transport timeout (default: 1s) [$TIMEOUT_CONTINUE]

mgmt:
      --mgmt.enabled                enable management API [$MGMT_ENABLED]
      --mgmt.listen=                listen on host:port (default: 0.0.0.0:8081) [$MGMT_LISTEN]

error:
      --error.enabled               enable html errors reporting [$ERROR_ENABLED]
      --error.template=             error message template file [$ERROR_TEMPLATE]

health-check:
      --health-check.enabled        enable automatic health-check [$HEALTH_CHECK_ENABLED]
      --health-check.interval=      automatic health-check interval (default: 300s) [$HEALTH_CHECK_INTERVAL]

throttle:
      --throttle.system=            throttle overall activity' (default: 0) [$THROTTLE_SYSTEM]
      --throttle.user=              limit req/sec per user and per proxy destination (default: 0) [$THROTTLE_USER]

plugin:
      --plugin.enabled              enable plugin support [$PLUGIN_ENABLED]
      --plugin.listen=              registration listen on host:port (default: 127.0.0.1:8081) [$PLUGIN_LISTEN]

Help Options:
  -h, --help                        Show this help message

Status

https://reproxy.io/#status

No Comments
Back to top