Custom proxy config
Add your own OpenResty directives to one domain, who may do it, what is refused, and how Synq tests the config and rolls it back if the edge rejects it.
Synq writes the OpenResty (nginx) configuration for every domain itself. For the few cases its settings don't cover, an organization admin can add a handful of raw directives to one domain. Synq checks them, tests the whole edge configuration and puts the previous version back automatically if the edge refuses it, so a typo can't take your other sites down.
Try the built-in settings first
Most needs have a safer switch. Upload size, timeouts, buffering and compression are in the project's Routing card on the Domains & Routes tab (Request limits); rewrites, redirects and response headers are there too; redirects, basic auth and IP rules are route rules. Setting the same directive in both places makes the edge test fail with a duplicate directive, and your change is rolled back.
Who can use it
- Reading: anyone who can see the domain can open the dialog and view the rendered config.
- Editing: organization owners and admins. Members with the Member role see "Only organization admins
can change this. You can still see the rendered config." The API needs the
domain:adminpermission. - Availability: every domain of a project on your servers, including free subdomains on your apps domain (they are ordinary domains). It isn't offered for a managed subdomain this server doesn't route ("Custom config is not available for this domain.").
Edit a domain's config
Open the editor
Go to Domains in the sidebar, open the domain's ⋯ menu and choose Custom config. The dialog is titled "Custom config for {hostname}".
Write your directives
There are two boxes:
| Box | Where the lines go |
|---|---|
| Server block | Into this domain's HTTP (port 80) and HTTPS (port 443) server blocks, after Synq's own settings. Extra location blocks go here. |
| location / block | At the end of the domain's location /, after the upstream and its proxy headers. |
A byte counter under each box shows "{used} / {max} bytes".
Save and apply
Press Save and apply. The result appears in the dialog (below).
To remove your directives, empty both boxes and save.
What happens when you save
- Validation. The API checks every line before anything is stored (see Rules). A refused
snippet is not saved; the error lists each problem with its box and line, for example
server line 2: `include` is not allowed: it loads other files into the edge config. - Apply. The config is stored on the domain and the project's live routes are re-applied. The edge writes
the new vhost file, runs
openresty -ton the whole configuration and reloads. - Rollback. If the test or the reload fails, the edge restores the previous vhost file and Synq restores the previous stored config. Your draft stays in the boxes so you can fix it.
The dialog reports one of:
| Result | Meaning |
|---|---|
| "Applied. The edge accepted the new config and reloaded." | Live now. |
| "Saved. It will be applied when the project deploys." | The project has no live deployment yet; the config goes live with the first deploy. |
| "The edge rejected this config, so the previous config was restored. Its error:" | Followed by nginx's own error message. Nothing changed on the server. |
| "Nothing changed." | The boxes match what's stored. |
Your directives are stored with the domain and rendered into its vhost every time Synq writes it (a deploy, a certificate renewal, a route change), so they survive redeploys.
Every save that reaches the edge is recorded in the Audit log as domain.custom_config_updated or, when the
edge refused it, domain.custom_config_rejected. The entry records line counts, sizes and directive names, not
the raw text, since a snippet may contain a header value or token.
Rendered config
Rendered config (read-only) shows the domain's vhost file exactly as the edge holds it. Your lines are
highlighted between the markers # synq-custom-config: begin (server) (or (location)) and
# synq-custom-config: end. Press Refresh to read it again. Before the domain is verified or the project
has deployed, it says that no vhost exists yet.
Rules
Raw config can't be proven safe by reading it, so the checks are layered: Synq refuses what must never reach a
shared edge, checks the structure, and then lets openresty -t have the final word.
Size and structure
- At most 8,192 bytes and 200 lines per box, and blocks nested at most 4 deep.
- Every statement ends with
;, and braces must balance. A snippet can't close the block it's placed in. - No braces inside quoted values or comments, quoted values stay on one line, and no control characters.
- Put
locationblocks in the Server block box, not in location / block.
Refused directives
The dialog summarizes the list: "Not allowed: include, load_module, Lua and njs code, init_* and worker_* settings, env, user, certificate paths, temp and cache paths, logs or root/alias outside this app, and upstreams on Synq's own ports." In full:
| Refused | Why |
|---|---|
include, load_module | Load other files or native code into the edge. |
Anything starting with lua, anything containing _by_lua, js_* (njs), perl* | Run code on the edge. |
init_*, worker_*, env, user, daemon, master_process, pid, lock_file, working_directory, thread_pool, pcre_jit, timer_resolution, ssl_engine and similar | Process-level settings of the shared edge. |
ssl_certificate*, ssl_password_file, ssl_trusted_certificate, ssl_client_certificate, ssl_crl, ssl_dhparam, ssl_session_ticket_key, ssl_stapling_file, ssl_conf_command | Certificates are managed by Synq. |
*_temp_path, *_cache_path, *_store, dav_*, xslt_*, auth_basic_user_file, create_full_put_path | Read or write files outside the route. Use basic auth rules instead of auth_basic_user_file. |
listen, server_name, server, http, upstream, events, stream, mail | Would change which traffic reaches the server block. |
map, geo, split_clients | Declare shared state for every route. |
Directives with restricted arguments
| Directive | Allowed |
|---|---|
access_log, error_log | Only files under /var/log/nginx/, /var/log/openresty/ or /usr/local/openresty/nginx/logs/, or access_log off. |
root, alias | One absolute path, without variables or .., inside the app's own static files. |
proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, grpc_pass, memcached_pass | A literal address (no variables), not a Unix socket, and not the loopback ports Synq itself uses (the API, the dashboard and OpenResty's management port). |
Examples
Add an HSTS header, so browsers remember to use HTTPS (Server block):
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;Keep response headers in the Server block box. An add_header inside location / makes nginx ignore every
add_header from the server level for that location, including headers Synq sets for you.
Answer robots.txt at the edge for a staging site (Server block):
location = /robots.txt {
default_type text/plain;
return 200 "User-agent: *\nDisallow: /\n";
}Hide a header your framework adds and pass an extra one to the app (location / block):
proxy_hide_header X-Powered-By;
proxy_set_header X-Forwarded-Host $host;From the API
curl -H "Authorization: Bearer $SYNQ_TOKEN" \
"$SYNQ_URL/api/domains/<domainId>/custom-config"
curl -X PUT -H "Authorization: Bearer $SYNQ_TOKEN" -H "Content-Type: application/json" \
-d '{"server":"add_header X-Frame-Options \"DENY\" always;","location":""}' \
"$SYNQ_URL/api/domains/<domainId>/custom-config"GET returns the stored server and location text, whether you may edit it, the limits and the rendered
vhost. PUT replaces both parts (an omitted field clears that part) and returns the same view plus a status of
applied, saved, rolled_back or unchanged; a rolled_back result carries the edge's error in message.
Related
Redirects, basic auth and security rules
Redirect paths, put a password on a site or a folder, rate-limit clients and block IPs, countries or bots, all enforced at the edge and applied instantly without a redeploy.
Cloudflare Tunnel and external proxies
Let Synq run a Cloudflare Tunnel on your server and route domains through it, or put your own tunnel, Cloudflare's proxy, Nginx Proxy Manager or a load balancer in front with External ingress & TLS.