mirror of https://github.com/telemt/telemt.git
Compare commits
No commits in common. "main" and "3.3.38" have entirely different histories.
|
|
@ -151,14 +151,6 @@ jobs:
|
|||
mkdir -p dist
|
||||
cp "target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}" dist/telemt
|
||||
|
||||
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
|
||||
STRIP_BIN=aarch64-linux-gnu-strip
|
||||
else
|
||||
STRIP_BIN=strip
|
||||
fi
|
||||
|
||||
"${STRIP_BIN}" dist/telemt
|
||||
|
||||
cd dist
|
||||
tar -czf "${{ matrix.asset }}.tar.gz" \
|
||||
--owner=0 --group=0 --numeric-owner \
|
||||
|
|
@ -287,14 +279,6 @@ jobs:
|
|||
mkdir -p dist
|
||||
cp "target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}" dist/telemt
|
||||
|
||||
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-musl" ]; then
|
||||
STRIP_BIN=aarch64-linux-musl-strip
|
||||
else
|
||||
STRIP_BIN=strip
|
||||
fi
|
||||
|
||||
"${STRIP_BIN}" dist/telemt
|
||||
|
||||
cd dist
|
||||
tar -czf "${{ matrix.asset }}.tar.gz" \
|
||||
--owner=0 --group=0 --numeric-owner \
|
||||
|
|
|
|||
16
LICENSE
16
LICENSE
|
|
@ -1,4 +1,4 @@
|
|||
######## TELEMT LICENSE 3.3 #########
|
||||
###### TELEMT Public License 3 ######
|
||||
##### Copyright (c) 2026 Telemt #####
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
|
@ -14,15 +14,11 @@ are preserved and complied with.
|
|||
The canonical version of this License is the English version.
|
||||
Official translations are provided for informational purposes only
|
||||
and for convenience, and do not have legal force. In case of any
|
||||
discrepancy, the English version of this License shall prevail
|
||||
|
||||
/----------------------------------------------------------\
|
||||
| Language | Location |
|
||||
|-------------|--------------------------------------------|
|
||||
| English | docs/LICENSE/TELEMT-LICENSE.en.md |
|
||||
| German | docs/LICENSE/TELEMT-LICENSE.de.md |
|
||||
| Russian | docs/LICENSE/TELEMT-LICENSE.ru.md |
|
||||
\----------------------------------------------------------/
|
||||
discrepancy, the English version of this License shall prevail.
|
||||
Available versions:
|
||||
- English in Markdown: docs/LICENSE/LICENSE.md
|
||||
- German: docs/LICENSE/LICENSE.de.md
|
||||
- Russian: docs/LICENSE/LICENSE.ru.md
|
||||
|
||||
### License Versioning Policy
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
|
||||
| Key | Type | Default |
|
||||
| --- | ---- | ------- |
|
||||
| [`include`](#cfg-top-include) | `String` (special directive) | — |
|
||||
| [`include`](#cfg-top-include) | `String` (special directive) | `null` |
|
||||
| [`show_link`](#cfg-top-show_link) | `"*"` or `String[]` | `[]` (`ShowLink::None`) |
|
||||
| [`dc_overrides`](#cfg-top-dc_overrides) | `Map<String, String or String[]>` | `{}` |
|
||||
| [`default_dc`](#cfg-top-default_dc) | `u8` | — (effective fallback: `2` in ME routing) |
|
||||
| [`default_dc`](#cfg-top-default_dc) | `u8` or `null` | `null` (effective fallback: `2` in ME routing) |
|
||||
|
||||
<a id="cfg-top-include"></a>
|
||||
- `include`
|
||||
|
|
@ -68,17 +68,17 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
|
||||
| Key | Type | Default |
|
||||
| --- | ---- | ------- |
|
||||
| [`data_path`](#cfg-general-data_path) | `String` | — |
|
||||
| [`data_path`](#cfg-general-data_path) | `String` or `null` | `null` |
|
||||
| [`prefer_ipv6`](#cfg-general-prefer_ipv6) | `bool` | `false` |
|
||||
| [`fast_mode`](#cfg-general-fast_mode) | `bool` | `true` |
|
||||
| [`use_middle_proxy`](#cfg-general-use_middle_proxy) | `bool` | `true` |
|
||||
| [`proxy_secret_path`](#cfg-general-proxy_secret_path) | `String` | `"proxy-secret"` |
|
||||
| [`proxy_config_v4_cache_path`](#cfg-general-proxy_config_v4_cache_path) | `String` | `"cache/proxy-config-v4.txt"` |
|
||||
| [`proxy_config_v6_cache_path`](#cfg-general-proxy_config_v6_cache_path) | `String` | `"cache/proxy-config-v6.txt"` |
|
||||
| [`ad_tag`](#cfg-general-ad_tag) | `String` | — |
|
||||
| [`middle_proxy_nat_ip`](#cfg-general-middle_proxy_nat_ip) | `IpAddr` | — |
|
||||
| [`proxy_secret_path`](#cfg-general-proxy_secret_path) | `String` or `null` | `"proxy-secret"` |
|
||||
| [`proxy_config_v4_cache_path`](#cfg-general-proxy_config_v4_cache_path) | `String` or `null` | `"cache/proxy-config-v4.txt"` |
|
||||
| [`proxy_config_v6_cache_path`](#cfg-general-proxy_config_v6_cache_path) | `String` or `null` | `"cache/proxy-config-v6.txt"` |
|
||||
| [`ad_tag`](#cfg-general-ad_tag) | `String` or `null` | `null` |
|
||||
| [`middle_proxy_nat_ip`](#cfg-general-middle_proxy_nat_ip) | `IpAddr` or `null` | `null` |
|
||||
| [`middle_proxy_nat_probe`](#cfg-general-middle_proxy_nat_probe) | `bool` | `true` |
|
||||
| [`middle_proxy_nat_stun`](#cfg-general-middle_proxy_nat_stun) | `String` | — |
|
||||
| [`middle_proxy_nat_stun`](#cfg-general-middle_proxy_nat_stun) | `String` or `null` | `null` |
|
||||
| [`middle_proxy_nat_stun_servers`](#cfg-general-middle_proxy_nat_stun_servers) | `String[]` | `[]` |
|
||||
| [`stun_nat_probe_concurrency`](#cfg-general-stun_nat_probe_concurrency) | `usize` | `8` |
|
||||
| [`middle_proxy_pool_size`](#cfg-general-middle_proxy_pool_size) | `usize` | `8` |
|
||||
|
|
@ -144,7 +144,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
| [`upstream_unhealthy_fail_threshold`](#cfg-general-upstream_unhealthy_fail_threshold) | `u32` | `5` |
|
||||
| [`upstream_connect_failfast_hard_errors`](#cfg-general-upstream_connect_failfast_hard_errors) | `bool` | `false` |
|
||||
| [`stun_iface_mismatch_ignore`](#cfg-general-stun_iface_mismatch_ignore) | `bool` | `false` |
|
||||
| [`unknown_dc_log_path`](#cfg-general-unknown_dc_log_path) | `String` | `"unknown-dc.txt"` |
|
||||
| [`unknown_dc_log_path`](#cfg-general-unknown_dc_log_path) | `String` or `null` | `"unknown-dc.txt"` |
|
||||
| [`unknown_dc_file_log_enabled`](#cfg-general-unknown_dc_file_log_enabled) | `bool` | `false` |
|
||||
| [`log_level`](#cfg-general-log_level) | `"debug"`, `"verbose"`, `"normal"`, or `"silent"` | `"normal"` |
|
||||
| [`disable_colors`](#cfg-general-disable_colors) | `bool` | `false` |
|
||||
|
|
@ -163,7 +163,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
| [`me_route_inline_recovery_attempts`](#cfg-general-me_route_inline_recovery_attempts) | `u32` | `3` |
|
||||
| [`me_route_inline_recovery_wait_ms`](#cfg-general-me_route_inline_recovery_wait_ms) | `u64` | `3000` |
|
||||
| [`fast_mode_min_tls_record`](#cfg-general-fast_mode_min_tls_record) | `usize` | `0` |
|
||||
| [`update_every`](#cfg-general-update_every) | `u64` | `300` |
|
||||
| [`update_every`](#cfg-general-update_every) | `u64` or `null` | `300` |
|
||||
| [`me_reinit_every_secs`](#cfg-general-me_reinit_every_secs) | `u64` | `900` |
|
||||
| [`me_hardswap_warmup_delay_min_ms`](#cfg-general-me_hardswap_warmup_delay_min_ms) | `u64` | `1000` |
|
||||
| [`me_hardswap_warmup_delay_max_ms`](#cfg-general-me_hardswap_warmup_delay_max_ms) | `u64` | `2000` |
|
||||
|
|
@ -205,7 +205,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
|
||||
<a id="cfg-general-data_path"></a>
|
||||
- `data_path`
|
||||
- **Constraints / validation**: `String` (optional).
|
||||
- **Constraints / validation**: `String` or `null`.
|
||||
- **Description**: Optional runtime data directory path.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-proxy_secret_path"></a>
|
||||
- `proxy_secret_path`
|
||||
- **Constraints / validation**: `String`. When omitted, the default path is `"proxy-secret"`. Empty values are accepted by TOML/serde but will likely fail at runtime (invalid file path).
|
||||
- **Constraints / validation**: `String` or `null`. If `null`, the effective cache path is `"proxy-secret"`. Empty values are accepted but will likely fail at runtime (invalid file path).
|
||||
- **Description**: Path to Telegram infrastructure `proxy-secret` cache file used by ME handshake/RPC auth. Telemt always tries a fresh download from `https://core.telegram.org/getProxySecret` first, caches it to this path on success, and falls back to reading the cached file (any age) on download failure.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-proxy_config_v4_cache_path"></a>
|
||||
- `proxy_config_v4_cache_path`
|
||||
- **Constraints / validation**: `String`. When set, must not be empty/whitespace-only.
|
||||
- **Constraints / validation**: `String` or `null`. When set, must not be empty/whitespace-only.
|
||||
- **Description**: Optional disk cache path for raw `getProxyConfig` (IPv4) snapshot. At startup Telemt tries to fetch a fresh snapshot first; on fetch failure or empty snapshot it falls back to this cache file when present and non-empty.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -265,7 +265,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-proxy_config_v6_cache_path"></a>
|
||||
- `proxy_config_v6_cache_path`
|
||||
- **Constraints / validation**: `String`. When set, must not be empty/whitespace-only.
|
||||
- **Constraints / validation**: `String` or `null`. When set, must not be empty/whitespace-only.
|
||||
- **Description**: Optional disk cache path for raw `getProxyConfigV6` (IPv6) snapshot. At startup Telemt tries to fetch a fresh snapshot first; on fetch failure or empty snapshot it falls back to this cache file when present and non-empty.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -275,7 +275,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-ad_tag"></a>
|
||||
- `ad_tag`
|
||||
- **Constraints / validation**: `String` (optional). When set, must be exactly 32 hex characters; invalid values are disabled during config load.
|
||||
- **Constraints / validation**: `String` or `null`. When set, must be exactly 32 hex characters; invalid values are disabled during config load.
|
||||
- **Description**: Global fallback sponsored-channel `ad_tag` (used when user has no override in `access.user_ad_tags`). An all-zero tag is accepted but has no effect (and is warned about) until replaced with a real tag from `@MTProxybot`.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-middle_proxy_nat_ip"></a>
|
||||
- `middle_proxy_nat_ip`
|
||||
- **Constraints / validation**: `IpAddr` (optional).
|
||||
- **Constraints / validation**: `IpAddr` or `null`.
|
||||
- **Description**: Manual public NAT IP override used as ME address material when set.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -967,8 +967,8 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-unknown_dc_log_path"></a>
|
||||
- `unknown_dc_log_path`
|
||||
- **Constraints / validation**: `String` (optional). Must be a safe path (no `..` components, parent directory must exist); unsafe paths are rejected at runtime.
|
||||
- **Description**: Log file path for unknown (non-standard) DC requests when `unknown_dc_file_log_enabled = true`. Omit this key to disable file logging.
|
||||
- **Constraints / validation**: `String` or `null`. Must be a safe path (no `..` components, parent directory must exist); unsafe paths are rejected at runtime.
|
||||
- **Description**: Log file path for unknown (non-standard) DC requests when `unknown_dc_file_log_enabled = true`. Set to `null` to disable file logging.
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
|
|
@ -1157,7 +1157,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-update_every"></a>
|
||||
- `update_every`
|
||||
- **Constraints / validation**: `u64` (seconds). If set, must be `> 0`. If this key is not explicitly set, legacy `proxy_secret_auto_reload_secs` and `proxy_config_auto_reload_secs` may be used (their effective minimum must be `> 0`).
|
||||
- **Constraints / validation**: `u64` (seconds) or `null`. If set, must be `> 0`. If `null`, legacy `proxy_secret_auto_reload_secs` and `proxy_config_auto_reload_secs` are used and their effective minimum must be `> 0`.
|
||||
- **Description**: Unified refresh interval for ME updater tasks (`getProxyConfig`, `getProxyConfigV6`, `getProxySecret`). When set, it overrides legacy proxy reload intervals.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -1450,7 +1450,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-proxy_secret_auto_reload_secs"></a>
|
||||
- `proxy_secret_auto_reload_secs`
|
||||
- **Constraints / validation**: Deprecated. Use `general.update_every`. When `general.update_every` is not explicitly set, the effective legacy refresh interval is `min(proxy_secret_auto_reload_secs, proxy_config_auto_reload_secs)` and must be `> 0`.
|
||||
- **Constraints / validation**: Deprecated. Use `general.update_every`. When `general.update_every` is `null`, the effective legacy refresh interval is `min(proxy_secret_auto_reload_secs, proxy_config_auto_reload_secs)` and must be `> 0`.
|
||||
- **Description**: Deprecated legacy proxy-secret refresh interval. Used only when `general.update_every` is not set.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -1463,7 +1463,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-proxy_config_auto_reload_secs"></a>
|
||||
- `proxy_config_auto_reload_secs`
|
||||
- **Constraints / validation**: Deprecated. Use `general.update_every`. When `general.update_every` is not explicitly set, the effective legacy refresh interval is `min(proxy_secret_auto_reload_secs, proxy_config_auto_reload_secs)` and must be `> 0`.
|
||||
- **Constraints / validation**: Deprecated. Use `general.update_every`. When `general.update_every` is `null`, the effective legacy refresh interval is `min(proxy_secret_auto_reload_secs, proxy_config_auto_reload_secs)` and must be `> 0`.
|
||||
- **Description**: Deprecated legacy ME config refresh interval. Used only when `general.update_every` is not set.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -1624,8 +1624,8 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
| Key | Type | Default |
|
||||
| --- | ---- | ------- |
|
||||
| [`show`](#cfg-general-links-show) | `"*"` or `String[]` | `"*"` |
|
||||
| [`public_host`](#cfg-general-links-public_host) | `String` | — |
|
||||
| [`public_port`](#cfg-general-links-public_port) | `u16` | — |
|
||||
| [`public_host`](#cfg-general-links-public_host) | `String` or `null` | `null` |
|
||||
| [`public_port`](#cfg-general-links-public_port) | `u16` or `null` | `null` |
|
||||
|
||||
<a id="cfg-general-links-show"></a>
|
||||
- `show`
|
||||
|
|
@ -1641,7 +1641,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-links-public_host"></a>
|
||||
- `public_host`
|
||||
- **Constraints / validation**: `String` (optional).
|
||||
- **Constraints / validation**: `String` or `null`.
|
||||
- **Description**: Public hostname/IP override used for generated `tg://` links (overrides detected IP).
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -1651,7 +1651,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-general-links-public_port"></a>
|
||||
- `public_port`
|
||||
- **Constraints / validation**: `u16` (optional).
|
||||
- **Constraints / validation**: `u16` or `null`.
|
||||
- **Description**: Public port override used for generated `tg://` links (overrides `server.port`).
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -1708,7 +1708,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
| Key | Type | Default |
|
||||
| --- | ---- | ------- |
|
||||
| [`ipv4`](#cfg-network-ipv4) | `bool` | `true` |
|
||||
| [`ipv6`](#cfg-network-ipv6) | `bool` | `false` |
|
||||
| [`ipv6`](#cfg-network-ipv6) | `bool` or `null` | `false` |
|
||||
| [`prefer`](#cfg-network-prefer) | `u8` | `4` |
|
||||
| [`multipath`](#cfg-network-multipath) | `bool` | `false` |
|
||||
| [`stun_use`](#cfg-network-stun_use) | `bool` | `true` |
|
||||
|
|
@ -1730,8 +1730,8 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-network-ipv6"></a>
|
||||
- `ipv6`
|
||||
- **Constraints / validation**: `bool`.
|
||||
- **Description**: Enables/disables IPv6 networking. When omitted, defaults to `false`.
|
||||
- **Constraints / validation**: `bool` or `null`. `null` means "auto-detect IPv6 availability".
|
||||
- **Description**: Enables/disables IPv6 when explicitly set; when `null`, Telemt will auto-detect IPv6 availability at runtime.
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
|
|
@ -1741,6 +1741,9 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
|
||||
# or: disable IPv6 explicitly
|
||||
# ipv6 = false
|
||||
|
||||
# or: let Telemt auto-detect
|
||||
# ipv6 = null
|
||||
```
|
||||
<a id="cfg-network-prefer"></a>
|
||||
- `prefer`
|
||||
|
|
@ -1839,16 +1842,16 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
| Key | Type | Default |
|
||||
| --- | ---- | ------- |
|
||||
| [`port`](#cfg-server-port) | `u16` | `443` |
|
||||
| [`listen_addr_ipv4`](#cfg-server-listen_addr_ipv4) | `String` | `"0.0.0.0"` |
|
||||
| [`listen_addr_ipv6`](#cfg-server-listen_addr_ipv6) | `String` | `"::"` |
|
||||
| [`listen_unix_sock`](#cfg-server-listen_unix_sock) | `String` | — |
|
||||
| [`listen_unix_sock_perm`](#cfg-server-listen_unix_sock_perm) | `String` | — |
|
||||
| [`listen_tcp`](#cfg-server-listen_tcp) | `bool` | — (auto) |
|
||||
| [`listen_addr_ipv4`](#cfg-server-listen_addr_ipv4) | `String` or `null` | `"0.0.0.0"` |
|
||||
| [`listen_addr_ipv6`](#cfg-server-listen_addr_ipv6) | `String` or `null` | `"::"` |
|
||||
| [`listen_unix_sock`](#cfg-server-listen_unix_sock) | `String` or `null` | `null` |
|
||||
| [`listen_unix_sock_perm`](#cfg-server-listen_unix_sock_perm) | `String` or `null` | `null` |
|
||||
| [`listen_tcp`](#cfg-server-listen_tcp) | `bool` or `null` | `null` (auto) |
|
||||
| [`proxy_protocol`](#cfg-server-proxy_protocol) | `bool` | `false` |
|
||||
| [`proxy_protocol_header_timeout_ms`](#cfg-server-proxy_protocol_header_timeout_ms) | `u64` | `500` |
|
||||
| [`proxy_protocol_trusted_cidrs`](#cfg-server-proxy_protocol_trusted_cidrs) | `IpNetwork[]` | `[]` |
|
||||
| [`metrics_port`](#cfg-server-metrics_port) | `u16` | — |
|
||||
| [`metrics_listen`](#cfg-server-metrics_listen) | `String` | — |
|
||||
| [`metrics_port`](#cfg-server-metrics_port) | `u16` or `null` | `null` |
|
||||
| [`metrics_listen`](#cfg-server-metrics_listen) | `String` or `null` | `null` |
|
||||
| [`metrics_whitelist`](#cfg-server-metrics_whitelist) | `IpNetwork[]` | `["127.0.0.1/32", "::1/128"]` |
|
||||
| [`max_connections`](#cfg-server-max_connections) | `u32` | `10000` |
|
||||
| [`accept_permit_timeout_ms`](#cfg-server-accept_permit_timeout_ms) | `u64` | `250` |
|
||||
|
|
@ -1865,8 +1868,8 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-server-listen_addr_ipv4"></a>
|
||||
- `listen_addr_ipv4`
|
||||
- **Constraints / validation**: `String` (optional). When set, must be a valid IPv4 address string.
|
||||
- **Description**: IPv4 bind address for TCP listener (omit this key to disable IPv4 bind).
|
||||
- **Constraints / validation**: `String` or `null`. When set, must be a valid IPv4 address string.
|
||||
- **Description**: IPv4 bind address for TCP listener (`null` disables IPv4 bind).
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
|
|
@ -1875,8 +1878,8 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-server-listen_addr_ipv6"></a>
|
||||
- `listen_addr_ipv6`
|
||||
- **Constraints / validation**: `String` (optional). When set, must be a valid IPv6 address string.
|
||||
- **Description**: IPv6 bind address for TCP listener (omit this key to disable IPv6 bind).
|
||||
- **Constraints / validation**: `String` or `null`. When set, must be a valid IPv6 address string.
|
||||
- **Description**: IPv6 bind address for TCP listener (`null` disables IPv6 bind).
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
|
|
@ -1885,7 +1888,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-server-listen_unix_sock"></a>
|
||||
- `listen_unix_sock`
|
||||
- **Constraints / validation**: `String` (optional). Must not be empty when set. Unix only.
|
||||
- **Constraints / validation**: `String` or `null`. Must not be empty when set. Unix only.
|
||||
- **Description**: Unix socket path for listener. When set, `server.listen_tcp` defaults to `false` (unless explicitly overridden).
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -1895,8 +1898,8 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-server-listen_unix_sock_perm"></a>
|
||||
- `listen_unix_sock_perm`
|
||||
- **Constraints / validation**: `String` (optional). When set, should be an octal permission string like `"0666"` or `"0777"`.
|
||||
- **Description**: Optional Unix socket file permissions applied after bind (chmod). When omitted, permissions are not changed (inherits umask).
|
||||
- **Constraints / validation**: `String` or `null`. When set, should be an octal permission string like `"0666"` or `"0777"`.
|
||||
- **Description**: Optional Unix socket file permissions applied after bind (chmod). `null` means "no change" (inherits umask).
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
|
|
@ -1906,7 +1909,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-server-listen_tcp"></a>
|
||||
- `listen_tcp`
|
||||
- **Constraints / validation**: `bool` (optional). When omitted, Telemt auto-detects:
|
||||
- **Constraints / validation**: `bool` or `null`. `null` means auto:
|
||||
- `true` when `listen_unix_sock` is not set
|
||||
- `false` when `listen_unix_sock` is set
|
||||
- **Description**: Explicit TCP listener enable/disable override.
|
||||
|
|
@ -1954,7 +1957,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-server-metrics_port"></a>
|
||||
- `metrics_port`
|
||||
- **Constraints / validation**: `u16` (optional).
|
||||
- **Constraints / validation**: `u16` or `null`.
|
||||
- **Description**: Prometheus-compatible metrics endpoint port. When set, enables the metrics listener (bind behavior can be overridden by `metrics_listen`).
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -1964,7 +1967,7 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
```
|
||||
<a id="cfg-server-metrics_listen"></a>
|
||||
- `metrics_listen`
|
||||
- **Constraints / validation**: `String` (optional). When set, must be in `IP:PORT` format.
|
||||
- **Constraints / validation**: `String` or `null`. When set, must be in `IP:PORT` format.
|
||||
- **Description**: Full metrics bind address (`IP:PORT`), overrides `metrics_port` and binds on the specified address only.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -2007,105 +2010,6 @@ This document lists all configuration keys accepted by `config.toml`.
|
|||
|
||||
Note: When `server.proxy_protocol` is enabled, incoming PROXY protocol headers are parsed from the first bytes of the connection and the client source address is replaced with `src_addr` from the header. For security, the peer source IP (the direct connection address) is verified against `server.proxy_protocol_trusted_cidrs`; if this list is empty, PROXY headers are rejected and the connection is considered untrusted.
|
||||
|
||||
## [server.conntrack_control]
|
||||
|
||||
Note: The conntrack-control worker runs **only on Linux**. On other operating systems it is not started; if `inline_conntrack_control` is `true`, a warning is logged. Effective operation also requires **CAP_NET_ADMIN** and a usable backend (`nft` or `iptables` / `ip6tables` on `PATH`). The `conntrack` utility is used for optional table entry deletes under pressure.
|
||||
|
||||
|
||||
| Key | Type | Default |
|
||||
| --- | ---- | ------- |
|
||||
| [`inline_conntrack_control`](#cfg-server-conntrack_control-inline_conntrack_control) | `bool` | `true` |
|
||||
| [`mode`](#cfg-server-conntrack_control-mode) | `String` | `"tracked"` |
|
||||
| [`backend`](#cfg-server-conntrack_control-backend) | `String` | `"auto"` |
|
||||
| [`profile`](#cfg-server-conntrack_control-profile) | `String` | `"balanced"` |
|
||||
| [`hybrid_listener_ips`](#cfg-server-conntrack_control-hybrid_listener_ips) | `IpAddr[]` | `[]` |
|
||||
| [`pressure_high_watermark_pct`](#cfg-server-conntrack_control-pressure_high_watermark_pct) | `u8` | `85` |
|
||||
| [`pressure_low_watermark_pct`](#cfg-server-conntrack_control-pressure_low_watermark_pct) | `u8` | `70` |
|
||||
| [`delete_budget_per_sec`](#cfg-server-conntrack_control-delete_budget_per_sec) | `u64` | `4096` |
|
||||
|
||||
<a id="cfg-server-conntrack_control-inline_conntrack_control"></a>
|
||||
- `inline_conntrack_control`
|
||||
- **Constraints / validation**: `bool`.
|
||||
- **Description**: Master switch for the runtime conntrack-control task: reconciles **raw/notrack** netfilter rules for listener ingress (see `mode`), samples load every second, and may run **`conntrack -D`** deletes for qualifying close events while **pressure mode** is active (see `delete_budget_per_sec`). When `false`, notrack rules are cleared and pressure-driven deletes are disabled.
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
[server.conntrack_control]
|
||||
inline_conntrack_control = true
|
||||
```
|
||||
<a id="cfg-server-conntrack_control-mode"></a>
|
||||
- `mode`
|
||||
- **Constraints / validation**: One of `tracked`, `notrack`, `hybrid` (case-insensitive; serialized lowercase).
|
||||
- **Description**: **`tracked`**: do not install telemt notrack rules (connections stay in conntrack). **`notrack`**: mark matching ingress TCP to `server.port` as notrack — targets are derived from `[[server.listeners]]` if any, otherwise from `server.listen_addr_ipv4` / `server.listen_addr_ipv6` (unspecified addresses mean “any” for that family). **`hybrid`**: notrack only for addresses listed in `hybrid_listener_ips` (must be non-empty; validated at load).
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
[server.conntrack_control]
|
||||
mode = "notrack"
|
||||
```
|
||||
<a id="cfg-server-conntrack_control-backend"></a>
|
||||
- `backend`
|
||||
- **Constraints / validation**: One of `auto`, `nftables`, `iptables` (case-insensitive; serialized lowercase).
|
||||
- **Description**: Which command set applies notrack rules. **`auto`**: use `nft` if present on `PATH`, else `iptables`/`ip6tables` if present. **`nftables`** / **`iptables`**: force that backend; missing binary means rules cannot be applied. The nft path uses table `inet telemt_conntrack` and a prerouting raw hook; iptables uses chain `TELEMT_NOTRACK` in the `raw` table.
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
[server.conntrack_control]
|
||||
backend = "auto"
|
||||
```
|
||||
<a id="cfg-server-conntrack_control-profile"></a>
|
||||
- `profile`
|
||||
- **Constraints / validation**: One of `conservative`, `balanced`, `aggressive` (case-insensitive; serialized lowercase).
|
||||
- **Description**: When **conntrack pressure mode** is active (`pressure_*` watermarks), caps idle and activity timeouts to reduce conntrack churn: e.g. **client first-byte idle** (`client.rs`), **direct relay activity timeout** (`direct_relay.rs`), and **middle-relay idle policy** caps (`middle_relay.rs` via `ConntrackPressureProfile::*_cap_secs` / `direct_activity_timeout_secs`). More aggressive profiles use shorter caps.
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
[server.conntrack_control]
|
||||
profile = "balanced"
|
||||
```
|
||||
<a id="cfg-server-conntrack_control-hybrid_listener_ips"></a>
|
||||
- `hybrid_listener_ips`
|
||||
- **Constraints / validation**: `IpAddr[]`. Required to be **non-empty** when `mode = "hybrid"`. Ignored for `tracked` / `notrack`.
|
||||
- **Description**: Explicit listener addresses that receive notrack rules in hybrid mode (split into IPv4 vs IPv6 rules by the implementation).
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
[server.conntrack_control]
|
||||
mode = "hybrid"
|
||||
hybrid_listener_ips = ["203.0.113.10", "2001:db8::1"]
|
||||
```
|
||||
<a id="cfg-server-conntrack_control-pressure_high_watermark_pct"></a>
|
||||
- `pressure_high_watermark_pct`
|
||||
- **Constraints / validation**: Must be within `[1, 100]`.
|
||||
- **Description**: Pressure mode **enters** when any of: connection fill vs `server.max_connections` (percentage, if `max_connections > 0`), **file-descriptor** usage vs process soft `RLIMIT_NOFILE`, **non-zero** `accept_permit_timeout` events in the last sample window, or **ME c2me send-full** counter delta. Entry compares relevant percentages against this high watermark (see `update_pressure_state` in `conntrack_control.rs`).
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
[server.conntrack_control]
|
||||
pressure_high_watermark_pct = 85
|
||||
```
|
||||
<a id="cfg-server-conntrack_control-pressure_low_watermark_pct"></a>
|
||||
- `pressure_low_watermark_pct`
|
||||
- **Constraints / validation**: Must be **strictly less than** `pressure_high_watermark_pct`.
|
||||
- **Description**: Pressure mode **clears** only after **three** consecutive one-second samples where all signals are at or below this low watermark and the accept-timeout / ME-queue deltas are zero (hysteresis).
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
[server.conntrack_control]
|
||||
pressure_low_watermark_pct = 70
|
||||
```
|
||||
<a id="cfg-server-conntrack_control-delete_budget_per_sec"></a>
|
||||
- `delete_budget_per_sec`
|
||||
- **Constraints / validation**: Must be `> 0`.
|
||||
- **Description**: Maximum number of **`conntrack -D`** attempts **per second** while pressure mode is active (token bucket refilled each second). Deletes run only for close events with reasons **timeout**, **pressure**, or **reset**; each attempt consumes a token regardless of outcome.
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
[server.conntrack_control]
|
||||
delete_budget_per_sec = 4096
|
||||
```
|
||||
|
||||
|
||||
## [server.api]
|
||||
|
||||
Note: This section also accepts the legacy alias `[server.admin_api]` (same schema as `[server.api]`).
|
||||
|
|
@ -2254,9 +2158,9 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
|
|||
| Key | Type | Default |
|
||||
| --- | ---- | ------- |
|
||||
| [`ip`](#cfg-server-listeners-ip) | `IpAddr` | — |
|
||||
| [`announce`](#cfg-server-listeners-announce) | `String` | — |
|
||||
| [`announce_ip`](#cfg-server-listeners-announce_ip) | `IpAddr` | — |
|
||||
| [`proxy_protocol`](#cfg-server-listeners-proxy_protocol) | `bool` | — |
|
||||
| [`announce`](#cfg-server-listeners-announce) | `String` or `null` | — |
|
||||
| [`announce_ip`](#cfg-server-listeners-announce_ip) | `IpAddr` or `null` | — |
|
||||
| [`proxy_protocol`](#cfg-server-listeners-proxy_protocol) | `bool` or `null` | `null` |
|
||||
| [`reuse_allow`](#cfg-server-listeners-reuse_allow) | `bool` | `false` |
|
||||
|
||||
<a id="cfg-server-listeners-ip"></a>
|
||||
|
|
@ -2271,7 +2175,7 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
|
|||
```
|
||||
<a id="cfg-server-listeners-announce"></a>
|
||||
- `announce`
|
||||
- **Constraints / validation**: `String` (optional). Must not be empty when set.
|
||||
- **Constraints / validation**: `String` or `null`. Must not be empty when set.
|
||||
- **Description**: Public IP/domain announced in proxy links for this listener. Takes precedence over `announce_ip`.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -2282,7 +2186,7 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
|
|||
```
|
||||
<a id="cfg-server-listeners-announce_ip"></a>
|
||||
- `announce_ip`
|
||||
- **Constraints / validation**: `IpAddr` (optional). Deprecated. Use `announce`.
|
||||
- **Constraints / validation**: `IpAddr` or `null`. Deprecated. Use `announce`.
|
||||
- **Description**: Deprecated legacy announce IP. During config load it is migrated to `announce` when `announce` is not set.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -2293,7 +2197,7 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
|
|||
```
|
||||
<a id="cfg-server-listeners-proxy_protocol"></a>
|
||||
- `proxy_protocol`
|
||||
- **Constraints / validation**: `bool` (optional). When set, overrides `server.proxy_protocol` for this listener.
|
||||
- **Constraints / validation**: `bool` or `null`. When set, overrides `server.proxy_protocol` for this listener.
|
||||
- **Description**: Per-listener PROXY protocol override.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -2447,9 +2351,9 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
|
|||
| [`tls_fetch_scope`](#cfg-censorship-tls_fetch_scope) | `String` | `""` |
|
||||
| [`tls_fetch`](#cfg-censorship-tls_fetch) | `Table` | built-in defaults |
|
||||
| [`mask`](#cfg-censorship-mask) | `bool` | `true` |
|
||||
| [`mask_host`](#cfg-censorship-mask_host) | `String` | — |
|
||||
| [`mask_host`](#cfg-censorship-mask_host) | `String` or `null` | `null` |
|
||||
| [`mask_port`](#cfg-censorship-mask_port) | `u16` | `443` |
|
||||
| [`mask_unix_sock`](#cfg-censorship-mask_unix_sock) | `String` | — |
|
||||
| [`mask_unix_sock`](#cfg-censorship-mask_unix_sock) | `String` or `null` | `null` |
|
||||
| [`fake_cert_len`](#cfg-censorship-fake_cert_len) | `usize` | `2048` |
|
||||
| [`tls_emulation`](#cfg-censorship-tls_emulation) | `bool` | `true` |
|
||||
| [`tls_front_dir`](#cfg-censorship-tls_front_dir) | `String` | `"tlsfront"` |
|
||||
|
|
@ -2536,8 +2440,8 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
|
|||
```
|
||||
<a id="cfg-censorship-mask_host"></a>
|
||||
- `mask_host`
|
||||
- **Constraints / validation**: `String` (optional).
|
||||
- If `mask_unix_sock` is set, `mask_host` must be omitted (mutually exclusive).
|
||||
- **Constraints / validation**: `String` or `null`.
|
||||
- If `mask_unix_sock` is set, `mask_host` must be `null` (mutually exclusive).
|
||||
- If `mask_host` is not set and `mask_unix_sock` is not set, Telemt defaults `mask_host` to `tls_domain`.
|
||||
- **Description**: Upstream mask host for TLS fronting relay.
|
||||
- **Example**:
|
||||
|
|
@ -2558,7 +2462,7 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
|
|||
```
|
||||
<a id="cfg-censorship-mask_unix_sock"></a>
|
||||
- `mask_unix_sock`
|
||||
- **Constraints / validation**: `String` (optional).
|
||||
- **Constraints / validation**: `String` or `null`.
|
||||
- Must not be empty when set.
|
||||
- Unix only; rejected on non-Unix platforms.
|
||||
- On Unix, must be \(\le 107\) bytes (path length limit).
|
||||
|
|
@ -2978,7 +2882,6 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
|
|||
| [`users`](#cfg-access-users) | `Map<String, String>` | `{"default": "000…000"}` |
|
||||
| [`user_ad_tags`](#cfg-access-user_ad_tags) | `Map<String, String>` | `{}` |
|
||||
| [`user_max_tcp_conns`](#cfg-access-user_max_tcp_conns) | `Map<String, usize>` | `{}` |
|
||||
| [`user_max_tcp_conns_global_each`](#cfg-access-user_max_tcp_conns_global_each) | `usize` | `0` |
|
||||
| [`user_expirations`](#cfg-access-user_expirations) | `Map<String, DateTime<Utc>>` | `{}` |
|
||||
| [`user_data_quota`](#cfg-access-user_data_quota) | `Map<String, u64>` | `{}` |
|
||||
| [`user_max_unique_ips`](#cfg-access-user_max_unique_ips) | `Map<String, usize>` | `{}` |
|
||||
|
|
@ -3023,20 +2926,6 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
|
|||
[access.user_max_tcp_conns]
|
||||
alice = 500
|
||||
```
|
||||
<a id="cfg-access-user_max_tcp_conns_global_each"></a>
|
||||
- `user_max_tcp_conns_global_each`
|
||||
- **Constraints / validation**: `usize`. `0` disables the inherited limit.
|
||||
- **Description**: Global per-user maximum concurrent TCP connections, applied when a user has **no positive** entry in `[access.user_max_tcp_conns]` (a missing key, or a value of `0`, both fall through to this setting). Per-user limits greater than `0` in `user_max_tcp_conns` take precedence.
|
||||
- **Example**:
|
||||
|
||||
```toml
|
||||
[access]
|
||||
user_max_tcp_conns_global_each = 200
|
||||
|
||||
[access.user_max_tcp_conns]
|
||||
alice = 500 # uses 500, not the global cap
|
||||
# bob has no entry → uses 200
|
||||
```
|
||||
<a id="cfg-access-user_expirations"></a>
|
||||
- `user_expirations`
|
||||
- **Constraints / validation**: `Map<String, DateTime<Utc>>`. Each value must be a valid RFC3339 / ISO-8601 datetime.
|
||||
|
|
@ -3138,13 +3027,13 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
|
|||
| [`weight`](#cfg-upstreams-weight) | `u16` | `1` |
|
||||
| [`enabled`](#cfg-upstreams-enabled) | `bool` | `true` |
|
||||
| [`scopes`](#cfg-upstreams-scopes) | `String` | `""` |
|
||||
| [`interface`](#cfg-upstreams-interface) | `String` | — |
|
||||
| [`bind_addresses`](#cfg-upstreams-bind_addresses) | `String[]` | — |
|
||||
| [`interface`](#cfg-upstreams-interface) | `String` or `null` | `null` |
|
||||
| [`bind_addresses`](#cfg-upstreams-bind_addresses) | `String[]` or `null` | `null` |
|
||||
| [`url`](#cfg-upstreams-url) | `String` | — |
|
||||
| [`address`](#cfg-upstreams-address) | `String` | — |
|
||||
| [`user_id`](#cfg-upstreams-user_id) | `String` | — |
|
||||
| [`username`](#cfg-upstreams-username) | `String` | — |
|
||||
| [`password`](#cfg-upstreams-password) | `String` | — |
|
||||
| [`user_id`](#cfg-upstreams-user_id) | `String` or `null` | `null` |
|
||||
| [`username`](#cfg-upstreams-username) | `String` or `null` | `null` |
|
||||
| [`password`](#cfg-upstreams-password) | `String` or `null` | `null` |
|
||||
|
||||
<a id="cfg-upstreams-type"></a>
|
||||
- `type`
|
||||
|
|
@ -3201,7 +3090,7 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
|
|||
```
|
||||
<a id="cfg-upstreams-interface"></a>
|
||||
- `interface`
|
||||
- **Constraints / validation**: `String` (optional).
|
||||
- **Constraints / validation**: `String` or `null`.
|
||||
- For `"direct"`: may be an IP address (used as explicit local bind) or an OS interface name (resolved to an IP at runtime; Unix only).
|
||||
- For `"socks4"`/`"socks5"`: supported only when `address` is an `IP:port` literal; when `address` is a hostname, interface binding is ignored.
|
||||
- For `"shadowsocks"`: passed to the shadowsocks connector as an optional outbound bind hint.
|
||||
|
|
@ -3220,7 +3109,7 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
|
|||
```
|
||||
<a id="cfg-upstreams-bind_addresses"></a>
|
||||
- `bind_addresses`
|
||||
- **Constraints / validation**: `String[]` (optional). Applies only to `type = "direct"`.
|
||||
- **Constraints / validation**: `String[]` or `null`. Applies only to `type = "direct"`.
|
||||
- Each entry should be an IP address string.
|
||||
- At runtime, Telemt selects an address that matches the target family (IPv4 vs IPv6). If `bind_addresses` is set and none match the target family, the connect attempt fails.
|
||||
- **Description**: Explicit local source addresses for outgoing direct TCP connects. When multiple addresses are provided, selection is round-robin.
|
||||
|
|
@ -3261,7 +3150,7 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
|
|||
```
|
||||
<a id="cfg-upstreams-user_id"></a>
|
||||
- `user_id`
|
||||
- **Constraints / validation**: `String` (optional). Only for `type = "socks4"`.
|
||||
- **Constraints / validation**: `String` or `null`. Only for `type = "socks4"`.
|
||||
- **Description**: SOCKS4 CONNECT user ID. Note: when a request scope is selected, Telemt may override this with the selected scope value.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -3273,7 +3162,7 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
|
|||
```
|
||||
<a id="cfg-upstreams-username"></a>
|
||||
- `username`
|
||||
- **Constraints / validation**: `String` (optional). Only for `type = "socks5"`.
|
||||
- **Constraints / validation**: `String` or `null`. Only for `type = "socks5"`.
|
||||
- **Description**: SOCKS5 username (for username/password authentication). Note: when a request scope is selected, Telemt may override this with the selected scope value.
|
||||
- **Example**:
|
||||
|
||||
|
|
@ -3285,7 +3174,7 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
|
|||
```
|
||||
<a id="cfg-upstreams-password"></a>
|
||||
- `password`
|
||||
- **Constraints / validation**: `String` (optional). Only for `type = "socks5"`.
|
||||
- **Constraints / validation**: `String` or `null`. Only for `type = "socks5"`.
|
||||
- **Description**: SOCKS5 password (for username/password authentication). Note: when a request scope is selected, Telemt may override this with the selected scope value.
|
||||
- **Example**:
|
||||
|
||||
|
|
|
|||
|
|
@ -128,8 +128,8 @@ WorkingDirectory=/opt/telemt
|
|||
ExecStart=/bin/telemt /etc/telemt/telemt.toml
|
||||
Restart=on-failure
|
||||
LimitNOFILE=65536
|
||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
NoNewPrivileges=true
|
||||
|
||||
[Install]
|
||||
|
|
|
|||
|
|
@ -128,8 +128,8 @@ WorkingDirectory=/opt/telemt
|
|||
ExecStart=/bin/telemt /etc/telemt/telemt.toml
|
||||
Restart=on-failure
|
||||
LimitNOFILE=65536
|
||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
NoNewPrivileges=true
|
||||
|
||||
[Install]
|
||||
|
|
|
|||
285
install.sh
285
install.sh
|
|
@ -8,20 +8,12 @@ CONFIG_DIR="${CONFIG_DIR:-/etc/telemt}"
|
|||
CONFIG_FILE="${CONFIG_FILE:-${CONFIG_DIR}/telemt.toml}"
|
||||
WORK_DIR="${WORK_DIR:-/opt/telemt}"
|
||||
TLS_DOMAIN="${TLS_DOMAIN:-petrovich.ru}"
|
||||
SERVER_PORT="${SERVER_PORT:-443}"
|
||||
USER_SECRET=""
|
||||
AD_TAG=""
|
||||
SERVICE_NAME="telemt"
|
||||
TEMP_DIR=""
|
||||
SUDO=""
|
||||
CONFIG_PARENT_DIR=""
|
||||
SERVICE_START_FAILED=0
|
||||
|
||||
PORT_PROVIDED=0
|
||||
SECRET_PROVIDED=0
|
||||
AD_TAG_PROVIDED=0
|
||||
DOMAIN_PROVIDED=0
|
||||
|
||||
ACTION="install"
|
||||
TARGET_VERSION="${VERSION:-latest}"
|
||||
|
||||
|
|
@ -33,37 +25,8 @@ while [ $# -gt 0 ]; do
|
|||
printf '[ERROR] %s requires a domain argument.\n' "$1" >&2
|
||||
exit 1
|
||||
fi
|
||||
TLS_DOMAIN="$2"; DOMAIN_PROVIDED=1; shift 2 ;;
|
||||
-p|--port)
|
||||
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
||||
printf '[ERROR] %s requires a port argument.\n' "$1" >&2; exit 1
|
||||
fi
|
||||
case "$2" in
|
||||
*[!0-9]*) printf '[ERROR] Port must be a valid number.\n' >&2; exit 1 ;;
|
||||
esac
|
||||
port_num="$(printf '%s\n' "$2" | sed 's/^0*//')"
|
||||
[ -z "$port_num" ] && port_num="0"
|
||||
if [ "${#port_num}" -gt 5 ] || [ "$port_num" -lt 1 ] || [ "$port_num" -gt 65535 ]; then
|
||||
printf '[ERROR] Port must be between 1 and 65535.\n' >&2; exit 1
|
||||
fi
|
||||
SERVER_PORT="$port_num"; PORT_PROVIDED=1; shift 2 ;;
|
||||
-s|--secret)
|
||||
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
||||
printf '[ERROR] %s requires a secret argument.\n' "$1" >&2; exit 1
|
||||
fi
|
||||
case "$2" in
|
||||
*[!0-9a-fA-F]*)
|
||||
printf '[ERROR] Secret must contain only hex characters.\n' >&2; exit 1 ;;
|
||||
esac
|
||||
if [ "${#2}" -ne 32 ]; then
|
||||
printf '[ERROR] Secret must be exactly 32 chars.\n' >&2; exit 1
|
||||
fi
|
||||
USER_SECRET="$2"; SECRET_PROVIDED=1; shift 2 ;;
|
||||
-a|--ad-tag|--ad_tag)
|
||||
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
||||
printf '[ERROR] %s requires an ad_tag argument.\n' "$1" >&2; exit 1
|
||||
fi
|
||||
AD_TAG="$2"; AD_TAG_PROVIDED=1; shift 2 ;;
|
||||
TLS_DOMAIN="$2"
|
||||
shift 2 ;;
|
||||
uninstall|--uninstall)
|
||||
if [ "$ACTION" != "purge" ]; then ACTION="uninstall"; fi
|
||||
shift ;;
|
||||
|
|
@ -96,17 +59,12 @@ cleanup() {
|
|||
trap cleanup EXIT INT TERM
|
||||
|
||||
show_help() {
|
||||
say "Usage: $0 [ <version> | install | uninstall | purge ] [ options ]"
|
||||
say "Usage: $0 [ <version> | install | uninstall | purge ] [ -d <domain> ] [ --help ]"
|
||||
say " <version> Install specific version (e.g. 3.3.15, default: latest)"
|
||||
say " install Install the latest version"
|
||||
say " uninstall Remove the binary and service"
|
||||
say " uninstall Remove the binary and service (keeps config and user)"
|
||||
say " purge Remove everything including configuration, data, and user"
|
||||
say ""
|
||||
say "Options:"
|
||||
say " -d, --domain Set TLS domain (default: petrovich.ru)"
|
||||
say " -p, --port Set server port (default: 443)"
|
||||
say " -s, --secret Set specific user secret (32 hex characters)"
|
||||
say " -a, --ad-tag Set ad_tag"
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
|
@ -123,13 +81,13 @@ get_realpath() {
|
|||
path_in="$1"
|
||||
case "$path_in" in /*) ;; *) path_in="$(pwd)/$path_in" ;; esac
|
||||
|
||||
if command -v realpath >/dev/null 2>&1; then
|
||||
if command -v realpath >/dev/null 2>&1; then
|
||||
if realpath_out="$(realpath -m "$path_in" 2>/dev/null)"; then
|
||||
printf '%s\n' "$realpath_out"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if command -v readlink >/dev/null 2>&1; then
|
||||
resolved_path="$(readlink -f "$path_in" 2>/dev/null || true)"
|
||||
if [ -n "$resolved_path" ]; then
|
||||
|
|
@ -162,14 +120,6 @@ get_svc_mgr() {
|
|||
else echo "none"; fi
|
||||
}
|
||||
|
||||
is_config_exists() {
|
||||
if [ -n "$SUDO" ]; then
|
||||
$SUDO sh -c '[ -f "$1" ]' _ "$CONFIG_FILE"
|
||||
else
|
||||
[ -f "$CONFIG_FILE" ]
|
||||
fi
|
||||
}
|
||||
|
||||
verify_common() {
|
||||
[ -n "$BIN_NAME" ] || die "BIN_NAME cannot be empty."
|
||||
[ -n "$INSTALL_DIR" ] || die "INSTALL_DIR cannot be empty."
|
||||
|
|
@ -177,7 +127,7 @@ verify_common() {
|
|||
[ -n "$CONFIG_FILE" ] || die "CONFIG_FILE cannot be empty."
|
||||
|
||||
case "${INSTALL_DIR}${CONFIG_DIR}${WORK_DIR}${CONFIG_FILE}" in
|
||||
*[!a-zA-Z0-9_./-]*) die "Invalid characters in paths." ;;
|
||||
*[!a-zA-Z0-9_./-]*) die "Invalid characters in paths. Only alphanumeric, _, ., -, and / allowed." ;;
|
||||
esac
|
||||
|
||||
case "$TARGET_VERSION" in *[!a-zA-Z0-9_.-]*) die "Invalid characters in version." ;; esac
|
||||
|
|
@ -195,11 +145,11 @@ verify_common() {
|
|||
if [ "$(id -u)" -eq 0 ]; then
|
||||
SUDO=""
|
||||
else
|
||||
command -v sudo >/dev/null 2>&1 || die "This script requires root or sudo."
|
||||
command -v sudo >/dev/null 2>&1 || die "This script requires root or sudo. Neither found."
|
||||
SUDO="sudo"
|
||||
if ! sudo -n true 2>/dev/null; then
|
||||
if ! [ -t 0 ]; then
|
||||
die "sudo requires a password, but no TTY detected."
|
||||
die "sudo requires a password, but no TTY detected. Aborting to prevent hang."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
|
@ -212,7 +162,21 @@ verify_common() {
|
|||
die "Safety check failed: CONFIG_FILE '$CONFIG_FILE' is a directory."
|
||||
fi
|
||||
|
||||
for cmd in id uname awk grep find rm chown chmod mv mktemp mkdir tr dd sed ps head sleep cat tar gzip; do
|
||||
for path in "$CONFIG_DIR" "$CONFIG_PARENT_DIR" "$WORK_DIR"; do
|
||||
check_path="$(get_realpath "$path")"
|
||||
case "$check_path" in
|
||||
/|/bin|/sbin|/usr|/usr/bin|/usr/sbin|/usr/local|/usr/local/bin|/usr/local/sbin|/usr/local/etc|/usr/local/share|/etc|/var|/var/lib|/var/log|/var/run|/home|/root|/tmp|/lib|/lib64|/opt|/run|/boot|/dev|/sys|/proc)
|
||||
die "Safety check failed: '$path' (resolved to '$check_path') is a critical system directory." ;;
|
||||
esac
|
||||
done
|
||||
|
||||
check_install_dir="$(get_realpath "$INSTALL_DIR")"
|
||||
case "$check_install_dir" in
|
||||
/|/etc|/var|/home|/root|/tmp|/usr|/usr/local|/opt|/boot|/dev|/sys|/proc|/run)
|
||||
die "Safety check failed: INSTALL_DIR '$INSTALL_DIR' is a critical system directory." ;;
|
||||
esac
|
||||
|
||||
for cmd in id uname grep find rm chown chmod mv mktemp mkdir tr dd sed ps head sleep cat tar gzip rmdir; do
|
||||
command -v "$cmd" >/dev/null 2>&1 || die "Required command not found: $cmd"
|
||||
done
|
||||
}
|
||||
|
|
@ -221,41 +185,14 @@ verify_install_deps() {
|
|||
command -v curl >/dev/null 2>&1 || command -v wget >/dev/null 2>&1 || die "Neither curl nor wget is installed."
|
||||
command -v cp >/dev/null 2>&1 || command -v install >/dev/null 2>&1 || die "Need cp or install"
|
||||
|
||||
if ! command -v setcap >/dev/null 2>&1 || ! command -v conntrack >/dev/null 2>&1; then
|
||||
if ! command -v setcap >/dev/null 2>&1; then
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
$SUDO apk add --no-cache libcap-utils libcap conntrack-tools >/dev/null 2>&1 || true
|
||||
$SUDO apk add --no-cache libcap-utils >/dev/null 2>&1 || $SUDO apk add --no-cache libcap >/dev/null 2>&1 || true
|
||||
elif command -v apt-get >/dev/null 2>&1; then
|
||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y -q libcap2-bin conntrack >/dev/null 2>&1 || {
|
||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get update -q >/dev/null 2>&1 || true
|
||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y -q libcap2-bin conntrack >/dev/null 2>&1 || true
|
||||
}
|
||||
elif command -v dnf >/dev/null 2>&1; then $SUDO dnf install -y -q libcap conntrack-tools >/dev/null 2>&1 || true
|
||||
elif command -v yum >/dev/null 2>&1; then $SUDO yum install -y -q libcap conntrack-tools >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
check_port_availability() {
|
||||
port_info=""
|
||||
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
port_info=$($SUDO ss -tulnp 2>/dev/null | grep -E ":${SERVER_PORT}([[:space:]]|$)" || true)
|
||||
elif command -v netstat >/dev/null 2>&1; then
|
||||
port_info=$($SUDO netstat -tulnp 2>/dev/null | grep -E ":${SERVER_PORT}([[:space:]]|$)" || true)
|
||||
elif command -v lsof >/dev/null 2>&1; then
|
||||
port_info=$($SUDO lsof -i :${SERVER_PORT} 2>/dev/null | grep LISTEN || true)
|
||||
else
|
||||
say "[WARNING] Network diagnostic tools (ss, netstat, lsof) not found. Skipping port check."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -n "$port_info" ]; then
|
||||
if printf '%s\n' "$port_info" | grep -q "${BIN_NAME}"; then
|
||||
say " -> Port ${SERVER_PORT} is in use by ${BIN_NAME}. Ignoring as it will be restarted."
|
||||
else
|
||||
say "[ERROR] Port ${SERVER_PORT} is already in use by another process:"
|
||||
printf ' %s\n' "$port_info"
|
||||
die "Please free the port ${SERVER_PORT} or change it and try again."
|
||||
$SUDO apt-get update -q >/dev/null 2>&1 || true
|
||||
$SUDO apt-get install -y -q libcap2-bin >/dev/null 2>&1 || true
|
||||
elif command -v dnf >/dev/null 2>&1; then $SUDO dnf install -y -q libcap >/dev/null 2>&1 || true
|
||||
elif command -v yum >/dev/null 2>&1; then $SUDO yum install -y -q libcap >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
|
@ -313,10 +250,10 @@ ensure_user_group() {
|
|||
|
||||
setup_dirs() {
|
||||
$SUDO mkdir -p "$WORK_DIR" "$CONFIG_DIR" "$CONFIG_PARENT_DIR" || die "Failed to create directories"
|
||||
|
||||
|
||||
$SUDO chown telemt:telemt "$WORK_DIR" && $SUDO chmod 750 "$WORK_DIR"
|
||||
$SUDO chown root:telemt "$CONFIG_DIR" && $SUDO chmod 750 "$CONFIG_DIR"
|
||||
|
||||
|
||||
if [ "$CONFIG_PARENT_DIR" != "$CONFIG_DIR" ] && [ "$CONFIG_PARENT_DIR" != "." ] && [ "$CONFIG_PARENT_DIR" != "/" ]; then
|
||||
$SUDO chown root:telemt "$CONFIG_PARENT_DIR" && $SUDO chmod 750 "$CONFIG_PARENT_DIR"
|
||||
fi
|
||||
|
|
@ -338,19 +275,17 @@ install_binary() {
|
|||
fi
|
||||
|
||||
$SUDO mkdir -p "$INSTALL_DIR" || die "Failed to create install directory"
|
||||
|
||||
$SUDO rm -f "$bin_dst" 2>/dev/null || true
|
||||
|
||||
if command -v install >/dev/null 2>&1; then
|
||||
$SUDO install -m 0755 "$bin_src" "$bin_dst" || die "Failed to install binary"
|
||||
else
|
||||
$SUDO rm -f "$bin_dst" 2>/dev/null || true
|
||||
$SUDO cp "$bin_src" "$bin_dst" && $SUDO chmod 0755 "$bin_dst" || die "Failed to copy binary"
|
||||
fi
|
||||
|
||||
$SUDO sh -c '[ -x "$1" ]' _ "$bin_dst" || die "Binary not executable: $bin_dst"
|
||||
|
||||
if command -v setcap >/dev/null 2>&1; then
|
||||
$SUDO setcap cap_net_bind_service,cap_net_admin=+ep "$bin_dst" 2>/dev/null || true
|
||||
$SUDO setcap cap_net_bind_service=+ep "$bin_dst" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -366,20 +301,11 @@ generate_secret() {
|
|||
}
|
||||
|
||||
generate_config_content() {
|
||||
conf_secret="$1"
|
||||
conf_tag="$2"
|
||||
escaped_tls_domain="$(printf '%s\n' "$TLS_DOMAIN" | tr -d '[:cntrl:]' | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
||||
|
||||
cat <<EOF
|
||||
[general]
|
||||
use_middle_proxy = true
|
||||
EOF
|
||||
|
||||
if [ -n "$conf_tag" ]; then
|
||||
echo "ad_tag = \"${conf_tag}\""
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
use_middle_proxy = false
|
||||
|
||||
[general.modes]
|
||||
classic = false
|
||||
|
|
@ -387,7 +313,7 @@ secure = false
|
|||
tls = true
|
||||
|
||||
[server]
|
||||
port = ${SERVER_PORT}
|
||||
port = 443
|
||||
|
||||
[server.api]
|
||||
enabled = true
|
||||
|
|
@ -398,73 +324,28 @@ whitelist = ["127.0.0.1/32"]
|
|||
tls_domain = "${escaped_tls_domain}"
|
||||
|
||||
[access.users]
|
||||
hello = "${conf_secret}"
|
||||
hello = "$1"
|
||||
EOF
|
||||
}
|
||||
|
||||
install_config() {
|
||||
if is_config_exists; then
|
||||
say " -> Config already exists at $CONFIG_FILE. Updating parameters..."
|
||||
|
||||
tmp_conf="${TEMP_DIR}/config.tmp"
|
||||
$SUDO cat "$CONFIG_FILE" > "$tmp_conf"
|
||||
|
||||
escaped_domain="$(printf '%s\n' "$TLS_DOMAIN" | tr -d '[:cntrl:]' | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
||||
|
||||
export AWK_PORT="$SERVER_PORT"
|
||||
export AWK_SECRET="$USER_SECRET"
|
||||
export AWK_DOMAIN="$escaped_domain"
|
||||
export AWK_AD_TAG="$AD_TAG"
|
||||
export AWK_FLAG_P="$PORT_PROVIDED"
|
||||
export AWK_FLAG_S="$SECRET_PROVIDED"
|
||||
export AWK_FLAG_D="$DOMAIN_PROVIDED"
|
||||
export AWK_FLAG_A="$AD_TAG_PROVIDED"
|
||||
|
||||
awk '
|
||||
BEGIN { ad_tag_handled = 0 }
|
||||
|
||||
ENVIRON["AWK_FLAG_P"] == "1" && /^[ \t]*port[ \t]*=/ { print "port = " ENVIRON["AWK_PORT"]; next }
|
||||
ENVIRON["AWK_FLAG_S"] == "1" && /^[ \t]*hello[ \t]*=/ { print "hello = \"" ENVIRON["AWK_SECRET"] "\""; next }
|
||||
ENVIRON["AWK_FLAG_D"] == "1" && /^[ \t]*tls_domain[ \t]*=/ { print "tls_domain = \"" ENVIRON["AWK_DOMAIN"] "\""; next }
|
||||
|
||||
ENVIRON["AWK_FLAG_A"] == "1" && /^[ \t]*ad_tag[ \t]*=/ {
|
||||
if (!ad_tag_handled) {
|
||||
print "ad_tag = \"" ENVIRON["AWK_AD_TAG"] "\"";
|
||||
ad_tag_handled = 1;
|
||||
}
|
||||
next
|
||||
}
|
||||
ENVIRON["AWK_FLAG_A"] == "1" && /^\[general\]/ {
|
||||
print;
|
||||
if (!ad_tag_handled) {
|
||||
print "ad_tag = \"" ENVIRON["AWK_AD_TAG"] "\"";
|
||||
ad_tag_handled = 1;
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
{ print }
|
||||
' "$tmp_conf" > "${tmp_conf}.new" && mv "${tmp_conf}.new" "$tmp_conf"
|
||||
|
||||
[ "$PORT_PROVIDED" -eq 1 ] && say " -> Updated port: $SERVER_PORT"
|
||||
[ "$SECRET_PROVIDED" -eq 1 ] && say " -> Updated secret for user 'hello'"
|
||||
[ "$DOMAIN_PROVIDED" -eq 1 ] && say " -> Updated tls_domain: $TLS_DOMAIN"
|
||||
[ "$AD_TAG_PROVIDED" -eq 1 ] && say " -> Updated ad_tag"
|
||||
|
||||
write_root "$CONFIG_FILE" < "$tmp_conf"
|
||||
rm -f "$tmp_conf"
|
||||
if [ -n "$SUDO" ]; then
|
||||
if $SUDO sh -c '[ -f "$1" ]' _ "$CONFIG_FILE"; then
|
||||
say " -> Config already exists at $CONFIG_FILE. Skipping creation."
|
||||
return 0
|
||||
fi
|
||||
elif [ -f "$CONFIG_FILE" ]; then
|
||||
say " -> Config already exists at $CONFIG_FILE. Skipping creation."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -z "$USER_SECRET" ]; then
|
||||
USER_SECRET="$(generate_secret)" || die "Failed to generate secret."
|
||||
fi
|
||||
toml_secret="$(generate_secret)" || die "Failed to generate secret."
|
||||
|
||||
generate_config_content "$USER_SECRET" "$AD_TAG" | write_root "$CONFIG_FILE" || die "Failed to install config"
|
||||
generate_config_content "$toml_secret" | write_root "$CONFIG_FILE" || die "Failed to install config"
|
||||
$SUDO chown root:telemt "$CONFIG_FILE" && $SUDO chmod 640 "$CONFIG_FILE"
|
||||
|
||||
say " -> Config created successfully."
|
||||
say " -> Configured secret for user 'hello': $USER_SECRET"
|
||||
say " -> Generated secret for default user 'hello': $toml_secret"
|
||||
}
|
||||
|
||||
generate_systemd_content() {
|
||||
|
|
@ -481,10 +362,9 @@ Group=telemt
|
|||
WorkingDirectory=$WORK_DIR
|
||||
ExecStart="${INSTALL_DIR}/${BIN_NAME}" "${CONFIG_FILE}"
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
LimitNOFILE=65536
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -515,7 +395,7 @@ install_service() {
|
|||
|
||||
$SUDO systemctl daemon-reload || true
|
||||
$SUDO systemctl enable "$SERVICE_NAME" || true
|
||||
|
||||
|
||||
if ! $SUDO systemctl start "$SERVICE_NAME"; then
|
||||
say "[WARNING] Failed to start service"
|
||||
SERVICE_START_FAILED=1
|
||||
|
|
@ -525,16 +405,16 @@ install_service() {
|
|||
$SUDO chown root:root "/etc/init.d/${SERVICE_NAME}" && $SUDO chmod 0755 "/etc/init.d/${SERVICE_NAME}"
|
||||
|
||||
$SUDO rc-update add "$SERVICE_NAME" default 2>/dev/null || true
|
||||
|
||||
|
||||
if ! $SUDO rc-service "$SERVICE_NAME" start 2>/dev/null; then
|
||||
say "[WARNING] Failed to start service"
|
||||
SERVICE_START_FAILED=1
|
||||
fi
|
||||
else
|
||||
cmd="\"${INSTALL_DIR}/${BIN_NAME}\" \"${CONFIG_FILE}\""
|
||||
if [ -n "$SUDO" ]; then
|
||||
if [ -n "$SUDO" ]; then
|
||||
say " -> Service manager not found. Start manually: sudo -u telemt $cmd"
|
||||
else
|
||||
else
|
||||
say " -> Service manager not found. Start manually: su -s /bin/sh telemt -c '$cmd'"
|
||||
fi
|
||||
fi
|
||||
|
|
@ -549,10 +429,9 @@ kill_user_procs() {
|
|||
if command -v pgrep >/dev/null 2>&1; then
|
||||
pids="$(pgrep -u telemt 2>/dev/null || true)"
|
||||
else
|
||||
pids="$(ps -ef 2>/dev/null | awk '$1=="telemt"{print $2}' || true)"
|
||||
[ -z "$pids" ] && pids="$(ps 2>/dev/null | awk '$2=="telemt"{print $1}' || true)"
|
||||
pids="$(ps -u telemt -o pid= 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$pids" ]; then
|
||||
for pid in $pids; do
|
||||
case "$pid" in ''|*[!0-9]*) continue ;; *) $SUDO kill "$pid" 2>/dev/null || true ;; esac
|
||||
|
|
@ -592,16 +471,15 @@ uninstall() {
|
|||
say ">>> Stage 5: Purging configuration, data, and user"
|
||||
$SUDO rm -rf "$CONFIG_DIR" "$WORK_DIR"
|
||||
$SUDO rm -f "$CONFIG_FILE"
|
||||
sleep 1
|
||||
$SUDO userdel telemt 2>/dev/null || $SUDO deluser telemt 2>/dev/null || true
|
||||
|
||||
if check_os_entity group telemt; then
|
||||
$SUDO groupdel telemt 2>/dev/null || $SUDO delgroup telemt 2>/dev/null || true
|
||||
if [ "$CONFIG_PARENT_DIR" != "$CONFIG_DIR" ] && [ "$CONFIG_PARENT_DIR" != "." ] && [ "$CONFIG_PARENT_DIR" != "/" ]; then
|
||||
$SUDO rmdir "$CONFIG_PARENT_DIR" 2>/dev/null || true
|
||||
fi
|
||||
$SUDO userdel telemt 2>/dev/null || $SUDO deluser telemt 2>/dev/null || true
|
||||
$SUDO groupdel telemt 2>/dev/null || $SUDO delgroup telemt 2>/dev/null || true
|
||||
else
|
||||
say "Note: Configuration and user kept. Run with 'purge' to remove completely."
|
||||
fi
|
||||
|
||||
|
||||
printf '\n====================================================================\n'
|
||||
printf ' UNINSTALLATION COMPLETE\n'
|
||||
printf '====================================================================\n\n'
|
||||
|
|
@ -615,28 +493,18 @@ case "$ACTION" in
|
|||
say "Starting installation of $BIN_NAME (Version: $TARGET_VERSION)"
|
||||
|
||||
say ">>> Stage 1: Verifying environment and dependencies"
|
||||
verify_common
|
||||
verify_install_deps
|
||||
verify_common; verify_install_deps
|
||||
|
||||
if is_config_exists && [ "$PORT_PROVIDED" -eq 0 ]; then
|
||||
ext_port="$($SUDO awk -F'=' '/^[ \t]*port[ \t]*=/ {gsub(/[^0-9]/, "", $2); print $2; exit}' "$CONFIG_FILE" 2>/dev/null || true)"
|
||||
if [ -n "$ext_port" ]; then
|
||||
SERVER_PORT="$ext_port"
|
||||
fi
|
||||
fi
|
||||
|
||||
check_port_availability
|
||||
|
||||
if [ "$TARGET_VERSION" != "latest" ]; then
|
||||
if [ "$TARGET_VERSION" != "latest" ]; then
|
||||
TARGET_VERSION="${TARGET_VERSION#v}"
|
||||
fi
|
||||
|
||||
|
||||
ARCH="$(detect_arch)"; LIBC="$(detect_libc)"
|
||||
FILE_NAME="${BIN_NAME}-${ARCH}-linux-${LIBC}.tar.gz"
|
||||
|
||||
|
||||
if [ "$TARGET_VERSION" = "latest" ]; then
|
||||
DL_URL="https://github.com/${REPO}/releases/latest/download/${FILE_NAME}"
|
||||
else
|
||||
else
|
||||
DL_URL="https://github.com/${REPO}/releases/download/${TARGET_VERSION}/${FILE_NAME}"
|
||||
fi
|
||||
|
||||
|
|
@ -653,7 +521,7 @@ case "$ACTION" in
|
|||
FILE_NAME="${BIN_NAME}-${ARCH}-linux-${LIBC}.tar.gz"
|
||||
if [ "$TARGET_VERSION" = "latest" ]; then
|
||||
DL_URL="https://github.com/${REPO}/releases/latest/download/${FILE_NAME}"
|
||||
else
|
||||
else
|
||||
DL_URL="https://github.com/${REPO}/releases/download/${TARGET_VERSION}/${FILE_NAME}"
|
||||
fi
|
||||
fetch_file "$DL_URL" "${TEMP_DIR}/${FILE_NAME}" || die "Download failed"
|
||||
|
|
@ -672,13 +540,13 @@ case "$ACTION" in
|
|||
|
||||
say ">>> Stage 4: Setting up environment (User, Group, Directories)"
|
||||
ensure_user_group; setup_dirs; stop_service
|
||||
|
||||
|
||||
say ">>> Stage 5: Installing binary"
|
||||
install_binary "$EXTRACTED_BIN" "${INSTALL_DIR}/${BIN_NAME}"
|
||||
|
||||
say ">>> Stage 6: Generating/Updating configuration"
|
||||
|
||||
say ">>> Stage 6: Generating configuration"
|
||||
install_config
|
||||
|
||||
|
||||
say ">>> Stage 7: Installing and starting service"
|
||||
install_service
|
||||
|
||||
|
|
@ -693,7 +561,7 @@ case "$ACTION" in
|
|||
printf ' INSTALLATION SUCCESS\n'
|
||||
printf '====================================================================\n\n'
|
||||
fi
|
||||
|
||||
|
||||
svc="$(get_svc_mgr)"
|
||||
if [ "$svc" = "systemd" ]; then
|
||||
printf 'To check the status of your proxy service, run:\n'
|
||||
|
|
@ -702,18 +570,15 @@ case "$ACTION" in
|
|||
printf 'To check the status of your proxy service, run:\n'
|
||||
printf ' rc-service %s status\n\n' "$SERVICE_NAME"
|
||||
fi
|
||||
|
||||
API_LISTEN="$($SUDO awk -F'"' '/^[ \t]*listen[ \t]*=/ {print $2; exit}' "$CONFIG_FILE" 2>/dev/null || true)"
|
||||
API_LISTEN="${API_LISTEN:-127.0.0.1:9091}"
|
||||
|
||||
|
||||
printf 'To get your user connection links (for Telegram), run:\n'
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
printf ' curl -s http://%s/v1/users | jq -r '\''.data[]? | "User: \\(.username)\\n\\(.links.tls[0] // empty)\\n"'\''\n' "$API_LISTEN"
|
||||
printf ' curl -s http://127.0.0.1:9091/v1/users | jq -r '\''.data[] | "User: \\(.username)\\n\\(.links.tls[0] // empty)\\n"'\''\n'
|
||||
else
|
||||
printf ' curl -s http://%s/v1/users\n' "$API_LISTEN"
|
||||
printf ' curl -s http://127.0.0.1:9091/v1/users\n'
|
||||
printf ' (Tip: Install '\''jq'\'' for a much cleaner output)\n'
|
||||
fi
|
||||
|
||||
|
||||
printf '\n====================================================================\n'
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
Loading…
Reference in New Issue