FlatRun uses Nginx as a reverse proxy to route incoming traffic to your deployments based on domain names. This enables you to run multiple applications on a single server, each with its own domain.
How It Works
- A request comes in for
blog.example.com - Nginx receives the request on port 80/443
- Nginx checks its virtual host configuration
- The request is forwarded to the appropriate container
- The container's response is sent back to the client
Nginx Configuration
Configure Nginx in your agent config:
nginx:
enabled: true
image: nginx:alpine
container_name: nginx
config_path: ""
reload_command: "nginx -s reload"
external: false
container_webroot_path: /usr/share/nginx/html | Option | Description |
|---|---|
enabled | Enable Nginx integration |
image | Docker image for Nginx |
container_name | Name of the Nginx container |
config_path | Path to config directory (auto-detected if empty) |
reload_command | Command to reload Nginx config |
external | Use external Nginx (not managed by FlatRun) |
Directory Structure
Nginx configuration is stored in the deployments path:
/var/flatrun/deployments/
└── nginx/
├── docker-compose.yml # Nginx container definition
├── conf.d/ # Virtual host configs
│ ├── blog.example.com.conf
│ └── api.example.com.conf
├── certs/ # SSL certificates
│ └── live/
│ └── example.com/
└── html/ # Static files, certbot webroot Virtual Host Configuration
FlatRun automatically generates virtual host configurations when you set up proxy for a deployment. A typical config looks like:
server {
listen 80;
server_name blog.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name blog.example.com;
ssl_certificate /etc/nginx/certs/live/blog.example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/live/blog.example.com/privkey.pem;
location / {
proxy_pass http://my-blog-wordpress:80;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
} Setting Up Proxy for a Deployment
Via UI
- Go to Deployments and select your deployment
- Go to the Overview tab
- In the Domain & SSL section, click "Set Up Proxy"
- Enter the domain name
- Select the container port
- Optionally enable SSL
- Click "Save"
Via API
curl -X POST "http://localhost:8090/api/proxy/setup/my-blog" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"domain": "blog.example.com",
"port": 80,
"ssl": true
}' Via service.yml
name: My Blog
networking:
expose: true
domain: blog.example.com
port: 80
ssl:
enabled: true
auto_renew: true Proxy Network
For Nginx to communicate with your deployment containers, they must be on the same Docker network. FlatRun uses a proxy network for this purpose.
# Create the proxy network (if not exists)
docker network create proxy
# Deployments should connect to this network
services:
web:
image: myapp
networks:
- default
- proxy
networks:
proxy:
external: true External Nginx
If you have an existing Nginx installation (on the host or another container), set external: true:
nginx:
enabled: true
external: true
config_path: /etc/nginx/conf.d
reload_command: "systemctl reload nginx" FlatRun will generate config files but won't manage the Nginx container.
Load Balancing
For deployments with multiple replicas, configure an upstream block:
upstream myapp_backend {
server myapp_1:3000;
server myapp_2:3000;
server myapp_3:3000;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://myapp_backend;
}
} WebSocket Support
Generated virtual hosts support WebSockets out of the box. The
Connection: upgrade header is sent only for requests that actually ask to
upgrade, so ordinary HTTP requests on the same domain keep upstream keep-alive intact.
Idle Timeout
The proxy read and send timeout defaults to 60 seconds. A WebSocket that
sits idle (no frames) for longer than that is closed by Nginx, which shows up as reconnect
loops on quiet connections. For deployments that hold long-lived sockets, raise the
per-domain timeout with proxy_timeout (in seconds):
domains:
- domain: app.example.com
service: app
container_port: 8080
proxy_timeout: 3600
ssl:
enabled: true
auto_cert: true proxy_timeout sets both the read and send timeouts; the connect timeout stays
at 60 seconds. Leave it unset to keep the 60-second default.
Custom Nginx Configuration
You can add custom configuration by creating files in the conf.d directory. FlatRun won't overwrite files it didn't create.
# Custom rate limiting
# /var/flatrun/deployments/nginx/conf.d/rate-limit.conf
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# Custom headers
# /var/flatrun/deployments/nginx/conf.d/security-headers.conf
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always; Troubleshooting
502 Bad Gateway
- Container is not running
- Container not on the proxy network
- Wrong port in proxy configuration
- Container name mismatch
Config Not Reloading
- Check Nginx syntax:
docker exec nginx nginx -t - Manually reload:
docker exec nginx nginx -s reload - Check FlatRun logs for errors
Route Saved but Returns Nothing
When you set up a domain whose target service or port has nothing listening, FlatRun saves the route and reloads, but reports a warning that the target is unreachable. Check the setup response (or the agent logs) for that warning, then confirm the service name and container port match a running container. The route is not blocked, so a target that comes up later starts serving without re-saving.
Domain Not Resolving
- Ensure DNS points to your server
- Check that port 80/443 is open in firewall
- Verify Nginx is listening on correct ports