// The JSON comments are somewhat brittle. Don't try anything too fancy. { // HTTP(S) address to listen on for websocket and long polling clients. Either a TCP host:port pair // or a path to Unix socket as "unix:/path/to/socket.sock". // The TCP port is either a numerical value or a canonical name, e.g. ":80" or ":https". May include // the host name, e.g. "localhost:80" or "hostname.example.com:https". // It could be blank: if TLS is not configured it will default to ":80", otherwise to ":443". // Can be overridden from the command line, see option --listen. "listen": ":6060", // Base URL path for serving streaming and large file API calls. // Can be overridden from the command line, see option --api_path. "api_path": "/", // Cache-Control header for static content in seconds. 39600 is 11 hours. "cache_control": 39600, // If true, do not attempt to negotiate websocket per message compression (RFC 7692.4). // It should be disabled (set to true) if you are using MSFT IIS as a reverse proxy. "ws_compression_disabled": false, // URL path for mounting the directory with static files. "static_mount": "/", // TCP host:port or unix:/path/to/socket to listen for gRPC clients. // Leave blank to disable gRPC support. // Could be overridden from the command line with --grpc_listen. "grpc_listen": ":16060", // Enable handling of gRPC keepalives https://github.com/grpc/grpc/blob/master/doc/keepalive.md // This sets server's GRPC_ARG_KEEPALIVE_TIME_MS to 60 seconds instead of the default 2 hours. "grpc_keepalive_enabled": true, // Salt for signing API key. 32 random bytes base64-encoded. Use 'keygen' tool (included in this // distro) to generate the API key and the salt. "api_key_salt": "T713/rYYgW7g4m3vG6zGRh7+FM1t0T8j13koXScOAj4=", // Maximum message size allowed from the clients in bytes (131072 = 128KB). // Media files with sizes greater than this limit are sent out of band. // Don't change this limit to a much higher value because it would likely cause failures: // * on Android & iOS due to a limit on the SQLite cursor window size; // * on the server-side with MySQL adapter due to the limit on the sort buffer size. "max_message_size": 131072, // Maximum number of subscribers per group topic. // This is the max number of subscribers to a group topic who may be configured to have specific access // permissions, like writing (posting), admin permissions, etc. // This setting is unrelated to channels readers (those have immutable read-only access). Channels have no // limit on readers. "max_subscriber_count": 128, // Maximum number of indexable tags per topic or user. "max_tag_count": 16, // If true, ordinary users cannot delete their accounts. "permanent_accounts": false, // URL path for exposing runtime stats. Disabled if the path is blank or "-". // Could be overriden from the command line with --expvar. "expvar": "/debug/vars", // URL path for server's internal status, useful when debugging. // Do not use this URL for docker status checks and some such. It's not a health check, // it is a debug endpoint. Disabled if the path is blank or "-". Could be overriden // from the command line with --server_status. // "server_status": "/debug/status", // Read IP address of the client from the HTTP header 'X-Forwarded-For'. // Useful when Tinode is behind a proxy. If missing, fallback to default RemoteAddr. "use_x_forwarded_for": true, // Add X-Frame-Options to HTTP response headers. It should be one of "DENY", "SAMEORIGIN", // "-" (disabled). If the option is missing then it's treated as SAMEORIGIN. "x_frame_options": "SAMEORIGIN", // 2-letter country code to assign to sessions by default when the country isn't specified // by the client explicitly and it's impossible to infer it. // If missing, the server will default to "US". "default_country_code": "", // Permit hard-deleting messages in p2p topics for both participants. // If it's set to 'false' then the message is only deleted for the peer who issued the command. // If it's 'true' then the message is deleted completely by either participant. // Changing the value affects the ability to hard-delete (the added or removed the D permission) // only for new topics going forward. "p2p_delete_enabled": true, // The maximum age of a message in seconds when it can be deleted by users with the 'D' permission. // E.g. 600 means messages up to 10 minutes old can be deleted, older than that cannot be deleted. // Missing or 0 means no age limit. // Does not affect topic owners: owners can delete any message. "msg_delete_age": 600, // Globally unique namespace. This is a special tag namespace which is used to store // aliases of the user. The alias is a tag which is not a valid Tinode user ID. "alias_tag": "alias", // Large media/blob handlers: large files/images included in messages. "media": { // The name of the media handler to use. "use_handler": "fs", // Maximum size of uploaded file (8MB here for testing, maybe increase to 100MB = 104857600 in prod) "max_size": 8388608, // Garbage collection periodicity in seconds: unused or abandoned uploads are deleted. "gc_period": 60, // The number of unused/abandoned entries to delete in one pass. "gc_block_size": 100, // Configurations of individual handlers. "handlers": { // File system storage. "fs": { // File system location to store uploaded files. In case of a cluster it // must be accessible by all cluster members, i.e. a network drive like https://www.samba.org/ "upload_dir": "uploads", // Cache-Control header to use for uploaded files. 86400 seconds = 24 hours. "cache_control": "max-age=86400", // Origin URLs allowed to download/upload files, e.g. ["https://www.example.com", "http://example.com", "https://*.example.com", "http://*.*.example.com"]. // Not necessary in most cases. // "cors_origins": ["*"] }, // Amazon AWS S3 storage. // See detailed explanation at https://pkg.go.dev/github.com/aws/aws-sdk-go/aws#Config "s3":{ // Use AWS console to get Access Key ID and Secret Access Key. // https://aws.amazon.com/blogs/security/wheres-my-secret-access-key/ "access_key_id": "your_s3_access_key_id", "secret_access_key": "your_s3_secret_access_key", // Region where the bucket is hosted. "region": "s3 region, like us-east-2", // Name of the S3 bucket. "bucket": "your_s3_bucket_name", // Set this to `true` to disable SSL when sending requests. Defaults to `false`. "disable_ssl": false, // Set this to `true` to force the request to use path-style addressing, // i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client // will use virtual hosted bucket addressing when possible // (`http://BUCKET.s3.amazonaws.com/KEY`). "force_path_style": false, // An optional endpoint URL (hostname only or fully qualified URI) // to override the default generated endpoint, or `""` to use the default generated endpoint. // The endpoint can be of any S3-compatible service, such as "minio-api.x.io". "endpoint": "", // Expiration time for presigned URLs in seconds. "presign_ttl": 3600, // Cache-Control header to use for uploaded files. 86400 seconds = 24 hours. "cache_control": "max-age=86400", // Origin URLs allowed to download files, e.g. ["https://www.example.com", "http://example.com"]. // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin "cors_origins": ["*"] } } }, // TLS (httpS) configuration. Applies to both web and gRPC interfaces. "tls": { // Enable TLS. "enabled": false, // Listen for connections on this port and redirect them to HTTPS port. // Cannot be a Unix socket. "http_redirect": ":80", // Add Strict-Transport-Security to headers, the value signifies age. // Zero or negative value turns it off. "strict_max_age": 604800, // Letsencrypt configuration. "autocert": { // Location of certificates. "cache": "/etc/letsencrypt/live/your.domain.here", // Contact address for this installation. LetsEncrypt will send // messages to this address in case of problems. Replace with your // own address or remove this line. "email": "noreply@example.com", // Domains served. Replace with your own domain name. "domains": ["whatever.example.com"] }, // If "autocert" config is not defined, read static certificates from // these locations. Ignored if "autocert" is defined. "cert_file": "/etc/httpd/conf/your.domain.crt", "key_file": "/etc/httpd/conf/your.domain.key" }, // Authentication configuration. "auth_config": { // Optional mapping of externally-visible authenticator names to internal names. // For example use ["my-auth:basic", "basic:"] to rename "basic" authenticator to // "my-auth" and make "basic" unaccessible by the old name. If you want to use REST-auth, then // the config is ["basic:rest", "rest:"]. // Default is identity mapping. "logical_names": [], // Basic (login + password) authentication. "basic": { // Add 'auth-name:username' to tags making user discoverable by username. "add_to_tags": true, // The minimum length of a login in unicode runes, i.e. "登录" is length 2, not 6. // The maximum length is 32 and it cannot be changed. "min_login_length": 4, // The minimum length of a password in unicode runes, "пароль" is length 6, not 12. // There is no limit on maximum length, but MySQL & PgSQL adapters have a limit of 32 bytes. "min_password_length": 6 }, // Token authentication "token": { // Lifetime of a security token in seconds. 1209600 = 2 weeks. "expire_in": 1209600, // Serial number of the token. Can be used to invalidate all issued tokens at once. "serial_num": 1, // Secret key (HMAC salt) for signing the tokens. Generate your own then keep it secret. // Any 32 random bytes base64 encoded. // // === IMPORTANT === // // CHANGE IT IN PRODUCTION!!! Otherwise anyone will be able to log in // to your server without the password. It's just random base64-encoded bytes, use any suitable // means to get it. For example: // Linux/Mac: // echo $(head -c 32 /dev/urandom | base64 | tr -d '\n') // Windows: // powershell -command "[Convert]::ToBase64String((1..32|%{[byte](Get-Random -Max 256)}))" "key": "wfaY2RgF2S1OQI/ZlK+LSrp1KB2jwAdGAIHQ7JZn+Kc=" }, // Short code authenticator for resetting passwords. "code": { // Lifetime of a security code in seconds. 900 seconds = 15 minutes. "expire_in": 900, // Number of times a user can try to enter the code. "max_retries": 3, // Length of the secret code. "code_length": 6 } }, // Database configuration "store_config": { // XTEA encryption key for user IDs and topic names. 16 random bytes base64-encoded. // Generate your own and keep it secret. Otherwise your user IDs will be predictable // and it will be easy to spam your users. "uid_key": "la6YsO+bNX/+XIkOqc5Svw==", // Maximum number of results fetched in one DB call. "max_results": 1024, // DB adapter name to communicate with the DB backend. // Must be one of the adapters from the list below. "use_adapter": "mysql", // Configurations of individual adapters. "adapters": { // PostgreSQL configuration. See https://godoc.org/github.com/jackc/pgx#Config // for other possible options. "postgres": { // PostgreSQL connection settings. // Don't change the username before reading the FAQ! "User": "postgres", "Passwd": "postgres", "Host": "localhost", "Port": "5432", "DBName": "tinode", "SSLMode": "disable", // DSN: alternative way of specifying database configuration, passed unchanged // to the driver. See https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING // "dsn": "postgresql://postgres:postgres@localhost:5432/tinode?sslmode=disable&connect_timeout=10", // PostgreSQL connection pool settings. // Maximum number of open connections to the database. Zero means unlimited. "max_open_conns": 50, // Maximum number of connections in the idle connection pool. Zero means no idle connections are retained. "max_idle_conns": 50, // Maximum amount of time a connection may be reused. Zero means unlimited. "conn_max_lifetime": 60, // Maximum amount of time waiting for a connection from the pool. Zero means no timeout. "sql_timeout": 10 }, // MySQL configuration. See https://godoc.org/github.com/go-sql-driver/mysql#Config // for other possible options. "mysql": { // MySQL connection settings via DSN. // See https://github.com/go-sql-driver/mysql#dsn-data-source-name for syntax. "dsn": "mysql://root:root@tcp(127.0.0.1:3306)/tinode?parseTime=true&collation=utf8mb4_0900_ai_ci", // Public tenant registry database. Tenant business data remains in tinode or per-tenant DBs. "tenant_registry_db": "hotgo", // Route tenant-scoped auth/business queries to each tenant's DB according to hotgo.im_tenant. "tenant_db_routing": true, // MySQL connection pool settings. // Maximum number of open connections to the database. Default: 0 (unlimited). "max_open_conns": 64, // Maximum number of connections in the idle connection pool. If negative or zero, // no idle connections are retained. "max_idle_conns": 64, // Maximum amount of time a connection may be reused (in seconds). "conn_max_lifetime": 60, // DB request timeout (in seconds). // If not set (or <= 0), DB queries and transactions will run without a timeout. "sql_timeout": 10 }, // RethinkDB configuration. See // https://godoc.org/github.com/rethinkdb/rethinkdb-go#ConnectOpts for other possible // options. "rethinkdb": { // Address(es) of RethinkDB node(s): either a string or an array of strings. "addresses": "localhost:28015", // Name of the main database. "database": "tinode" }, // MongoDB configuration. "mongodb": { // Connection string https://www.mongodb.com/docs/manual/reference/connection-string/ // Options configured with the 'uri' connection string override all other options // (only 'uri' is sent to the server, all other options are ignored). // If you are using Atlas, then you MUST use 'uri' to connect. See here: // https://www.mongodb.com/docs/manual/reference/connection-string/#std-label-connections-dns-seedlist // Something like // "uri": "mongodb+srv://CREDENTIALS@PROJECT.gmuaq.mongodb.net/DATABASE?retryWrites=true&w=majority", "uri": "", // The only supported server API version is "1". May or maynot be needed depending on server version. "api_version": "", // Address(es) of MongoDB node(s): either a string or an array of strings. "addresses": "localhost:27017", // Name of the main database. "database": "tinode", // Name of replica set of mongodb instance. Remove this line to use a standalone instance. // If replica_set is disabled, transactions will be disabled as well. "replica_set": "rs0", // Authentication options. Uncomment if auth is configured on your MongoDB. // Authentication mechanism. See https://www.mongodb.com/docs/manual/core/authentication/ // Default "SCRAM-SHA-256" // "auth_mechanism": "SCRAM-SHA-256", // The name of database that has the collection with the user credentials. Default "admin". // "auth_source": "admin", // Username: // "username": "tinode", // Password: // "password": "tinode", // Driver's TLS configuration. Uncomment to enable TLS. // "tls": true, // Path to the client certificate. Optional. // "tls_cert_file": "/path/to/cert_file", // Path to private key. Optional. // "tls_private_key": "/path/to/private_key", // Specifies whether or not certificates and hostnames received from the server should be validated. // Not recommended to enable in production. Default is false. // "tls_skip_verify": false } } }, // Account validators (email or SMS or captcha). "acc_validation": { // Email validator config. "email": { // Restrict use of "email" namespace: make users searchable by their emails, // disable manual creation of email: tags. "add_to_tags": true, // List of authentication levels which require this validation method. // Remove this line to disable email validation. "required": ["auth"], // Configuration passed to the validator unchanged. "config": { // Address of the host where the Tinode server is running. This will be used // in URLs in the email. "host_url": "http://localhost:6060/", // Address of the SMPT server to use. "smtp_server": "smtp.example.com", // SMTP port to use. "25" for basic email RFC 5321 (2821, 821), "587" for RFC 3207 (TLS). "smtp_port": "25", // RFC 5322 email address to show in the From: field. "sender": "\"Tinode\" ", // Optional login to use for authentication; if missing, the connection is not authenticated. "login": "john.doe@example.com", // Password to use when authenticating the sender; used only if "login" is provided. "sender_password": "your-password-here", // Authentication mechanism to use, optional. One of "login", "cram-md5", "plain" (default). "auth_mechanism": "login", // FQDN to use in SMTP HELO/EHLO command; if missing, the hostname from "host_url" is used. "smtp_helo_host": "example.com", // Skip verification of the server's certificate chain and host name. // In this mode, TLS is susceptible to man-in-the-middle attacks. "insecure_skip_verify": false, // Optional list of human languages to try to load templates for. If you don't care about i18n, // leave it blank or remove. The first language in the list is the default language. "languages": ["en", "es", "fr", "pt", "ru", "uk", "vi", "zh", "zh-TW"], // Message template for credential validation. // The file path itself is treated as a template. It's resolved by using the // "languages" field above. One template per language. // See the template file for the explanation of the expected structure. "validation_templ": "./templ/email-validation-{{.Language}}.templ", // Message template for resetting authentication secret. // One template per language. See email-validation-en template for the explanation // of the expected structure. "reset_secret_templ": "./templ/email-password-reset-{{.Language}}.templ", // Allow this many confirmation attempts before blocking the credential. "max_retries": 3, // List of email domains allowed to be used for registration. // Missing or empty list means any email domain is accepted. "domains": [], // Dummy response to accept. // // === IMPORTANT === // // REMOVE IN PRODUCTION!!! Otherwise anyone will be able to register // with fake emails. "debug_response": "123456" } }, // Placeholder validator for SMS and voice validation. Disabled by default. // Use something like twilio.com or sinch.com in production. "tel": { "add_to_tags": true, "config": { // Address of the host where the Tinode server is running. This will be used // in URLs in the SMS. "host_url": "http://localhost:6060/", // Optional list of locales to try to load templates for. If you don't care about i18n, // leave it blank or remove. The first language in the list is the default language. "languages": ["en", "es", "fr", "pt", "ru", "uk", "vi", "zh", "zh-TW"], // String to use in the From field of the SMS. "sender": "Tinode", // Message template for credential validation and password reset. The file path itself is // treated as a template. It's resolved by using the "languages" field above. One template // per language. "universal_templ": "./templ/sms-universal-{{.Language}}.templ", // Allow this many confirmation attempts before blocking the credential. "max_retries": 3, // Twilio configuration (optional). //"twilio_conf": { // "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // "auth_token": "f2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //}, // Dummy response to accept. // // === IMPORTANT === // // REMOVE IN PRODUCTION!!! Otherwise anyone will be able to register // with fake phone numbers. "debug_response": "123456" } } }, // Configuration for stale account garbage collector: remove // stale unvalidated user accounts which have been last updated at least // 'gc_min_account_age' hours ago. "acc_gc_config": { "enabled": true, // How often to run GC (seconds). "gc_period": 3600, // Number of accounts to delete in one pass. "gc_block_size": 10, // Minimum hours since account was last modified. "gc_min_account_age": 30 }, // Configuration of push notifications. "push": [ { // Notificator which writes to STDOUT. Useful for debugging. "name":"stdout", "config": { // Disabled. "enabled": false } }, { // Google FCM notificator. "name":"fcm", "config": { // Disabled. Won't work without the server key anyway. See below. "enabled": false, // Firebase project ID. "project_id": "your-project-id", // Service account credentials as json. // See instructions how to download the service account credentials file: // https://cloud.google.com/iam/docs/creating-managing-service-account-keys // Then insert the file contents here. Yes, this is convoluted, but that's Google's fault. "credentials": { "type": "service_account", "project_id": "your-project-id", "private_key_id": "some-random-looking-hex-number", "private_key": "-----BEGIN PRIVATE KEY----- base64-encoded bits of your private key \n-----END PRIVATE KEY-----\n", "client_email": "firebase-adminsdk-abc123@your-project-id.iam.gserviceaccount.com", "client_id": "1234567890123456789", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-abc123%40your-project-id.iam.gserviceaccount.com" }, // An alternative way to provide Firebase service account credentials. "credentials_file": "/path/to/service-account-file-with-credentials.json", // Time in seconds before notification is discarded (by Google) if undelivered. "time_to_live": 3600, // Payload of AndroidNotification. If enabled, this will take precedence over data payload. "android": { // Set to false to push a data-only message. "enabled": false, // Android drawable resource ID to use as a notification icon. "icon": "ic_logo_push", // Notification color. "color": "#3949AB", // Name of intent filter which will catch this notification. "click_action": ".MessageActivity", // Notification of a new message. You can include custom "icon", "color", "click_action" // into this section and it will override the value above. "msg": { // Literal title string. Not recommended because it's not localized. "title": "", // Literal message body. Not recommended because it's not localized. "body": "", // Android string resource ID to use as a notification title. Localized. // Takes precedence over "title". "new_message" is "New message" in Tindroid. "title_loc_key": "new_message", // Android string resource ID to use as a notification body. Localized. // Takes precedence over "body". "body_loc_key": "" }, // Notification of a new subscription. Same rules as section "msg" above. "sub": { // Android resource string ID to use as notification title. Localized. // "new_chat" is "New chat" in Tindroid. "title_loc_key": "new_chat", // Android resource string ID to use as notification body. Localized. "body_loc_key": "" } } } }, { // Tinode Push Gateway, see https://github.com/tinode/chat/tree/master/server/push/tnpg. "name":"tnpg", "config": { // Disabled. Configure first then enable. "enabled": false, // Short name (URL) of the organization you registered at console.tinode.co. "org": "test", // Authentication token obtained from console.tinode.co "token": "jwt-security-token-obtained-from-console.tinode.co", } } ], // Configuration for voice and video calls. "webrtc": { // Disabled. Won't work without functioning ice_servers (see below). "enabled": false, // Timeout in seconds before a video/voice call is dropped if not answered. "call_establishment_timeout": 30, // Interactive Communication Establishment (ICE) STUN and TURN server configuration for video calls. // You need to configure your own servers or consider https://www.metered.ca/tools/openrelay/. // Video calls will not work if both parties are behind NAT and no ICE servers are configured. "ice_servers": [ { "urls": [ "stun:stun.example.com" ] }, { "username": "user-name-to-use-for-authentication-with-the-server", "credential": "your-password", "urls": [ "turn:turn.example.com:80?transport=udp", "turn:turn.example.com:3478?transport=udp", "turn:turn.example.com:80?transport=tcp", "turn:turn.example.com:3478?transport=tcp", "turns:turn.example.com:443?transport=tcp", "turns:turn.example.com:5349?transport=tcp" ] } ], // An alternative way to provide STUN/TURN configuration. "ice_servers_file": "/path/to/ice-servers-config.json" }, // Cluster-mode configuration. "cluster_config": { // Name of this node. Can be assigned from the command line as --cluster_self. // Empty string disables clustering. "self": "", // List of available nodes. "nodes": [ // Name and TCP address of every node in the cluster. The ports 12001..12003 // are cluster communication ports. They don't need to be exposed to end-users. {"name": "one", "addr":"localhost:12001"}, {"name": "two", "addr":"localhost:12002"}, {"name": "three", "addr":"localhost:12003"} ], // Failover config. No need to change unless you are doing something unusual. "failover": { // Failover is enabled. "enabled": true, // Time in milliseconds between heartbeats. "heartbeat": 100, // Initiate leader election when the leader is not available for this many heartbeats. "vote_after": 8, // Consider node failed when it missed this many heartbeats. "node_fail_after": 16 } }, // Configuration of plugins. "plugins": [ { // Enable or disable this plugin. "enabled": false, // Name of the plugin, must be unique. "name": "python_chat_bot", // Timeout in microseconds. "timeout": 20000, // Events to send to the plugin. "filters": { // Account creation events. "account": "C" }, // Error code to use in case plugin has failed; 0 means to ignore the failures. "failure_code": 0, // Text of an error message to report in case of plugin failure. "failure_text": null, // Address of the plugin. "service_addr": "tcp://localhost:40051" } ] }