0
# Server and Deployment
1
2
Sanic provides comprehensive server configuration and deployment options for production environments. This includes multi-worker support, SSL/TLS configuration, various server protocols, process management, and production-ready features.
3
4
## Capabilities
5
6
### Server Execution
7
8
Core methods for running Sanic applications with various configuration options.
9
10
```python { .api }
11
def run(
12
host: str = "127.0.0.1",
13
port: int = 8000,
14
debug: bool = False,
15
ssl: dict = None,
16
sock: socket.socket = None,
17
workers: int = 1,
18
protocol: type = None,
19
backlog: int = 100,
20
stop_event: asyncio.Event = None,
21
register_sys_signals: bool = True,
22
run_multiple: bool = False,
23
run_async: bool = False,
24
connections: set = None,
25
signal: Signal = None,
26
state: dict = None,
27
asyncio_server_kwargs: dict = None,
28
return_asyncio_server: bool = False,
29
**kwargs
30
):
31
"""
32
Run the Sanic server.
33
34
Parameters:
35
- host: Server host address
36
- port: Server port number
37
- debug: Enable debug mode
38
- ssl: SSL configuration dictionary
39
- sock: Custom socket object
40
- workers: Number of worker processes
41
- protocol: Custom protocol class
42
- backlog: Connection backlog size
43
- stop_event: Event for graceful shutdown
44
- register_sys_signals: Register system signal handlers
45
- run_multiple: Enable multi-worker mode
46
- run_async: Run server asynchronously
47
- connections: Connection tracking set
48
- signal: Signal object for coordination
49
- state: Shared state dictionary
50
- asyncio_server_kwargs: Additional asyncio server arguments
51
- return_asyncio_server: Return server object instead of running
52
53
Returns:
54
- None (runs server) or server object (if return_asyncio_server=True)
55
"""
56
57
def create_server(
58
host: str = "127.0.0.1",
59
port: int = 8000,
60
return_asyncio_server: bool = False,
61
asyncio_server_kwargs: dict = None,
62
**kwargs
63
):
64
"""
65
Create server instance without running it.
66
67
Parameters:
68
- host: Server host address
69
- port: Server port number
70
- return_asyncio_server: Return asyncio server object
71
- asyncio_server_kwargs: Additional asyncio server arguments
72
73
Returns:
74
- Server instance or asyncio server object
75
"""
76
77
async def serve(
78
host: str = "127.0.0.1",
79
port: int = 8000,
80
ssl: dict = None,
81
sock: socket.socket = None,
82
protocol: type = None,
83
backlog: int = 100,
84
connections: set = None,
85
**kwargs
86
):
87
"""
88
Serve the application asynchronously.
89
90
Parameters:
91
- host: Server host address
92
- port: Server port number
93
- ssl: SSL configuration
94
- sock: Custom socket
95
- protocol: Custom protocol class
96
- backlog: Connection backlog
97
- connections: Connection tracking
98
99
Returns:
100
- Server object
101
"""
102
```
103
104
### Multi-Worker Deployment
105
106
Scale applications horizontally using multiple worker processes.
107
108
```python { .api }
109
def run_multiple(
110
workers: int,
111
host: str = "127.0.0.1",
112
port: int = 8000,
113
ssl: dict = None,
114
sock: socket.socket = None,
115
**kwargs
116
):
117
"""
118
Run server with multiple worker processes.
119
120
Parameters:
121
- workers: Number of worker processes
122
- host: Server host address
123
- port: Server port number
124
- ssl: SSL configuration
125
- sock: Custom socket
126
127
Features:
128
- Process-based parallelism
129
- Shared socket for load balancing
130
- Graceful worker management
131
- Signal handling for coordinated shutdown
132
"""
133
134
# Worker configuration options
135
WORKERS: int = 1 # Number of worker processes
136
WORKER_CLASS: str = "sanic.worker.GunicornWorker" # Worker class
137
WORKER_CONNECTIONS: int = 1000 # Max connections per worker
138
WORKER_MAX_REQUESTS: int = 0 # Max requests before worker restart
139
WORKER_MAX_REQUESTS_JITTER: int = 0 # Random jitter for max requests
140
```
141
142
### SSL/TLS Configuration
143
144
Secure server deployment with SSL/TLS encryption.
145
146
```python { .api }
147
# SSL configuration dictionary structure
148
ssl_config = {
149
"cert": str, # Certificate file path
150
"key": str, # Private key file path
151
"ca_certs": str, # CA certificates file path (optional)
152
"ciphers": str, # Cipher suites (optional)
153
"ssl_version": int, # SSL/TLS version (optional)
154
"do_handshake_on_connect": bool, # Handshake behavior (optional)
155
"check_hostname": bool, # Hostname verification (optional)
156
"certfile": str, # Alias for cert (optional)
157
"keyfile": str, # Alias for key (optional)
158
"password": str, # Private key password (optional)
159
}
160
161
# Example SSL configurations
162
ssl_basic = {
163
"cert": "/path/to/certificate.pem",
164
"key": "/path/to/private_key.pem"
165
}
166
167
ssl_advanced = {
168
"cert": "/path/to/certificate.pem",
169
"key": "/path/to/private_key.pem",
170
"ca_certs": "/path/to/ca_certificates.pem",
171
"ciphers": "ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS",
172
"ssl_version": 2, # ssl.PROTOCOL_TLS
173
"check_hostname": False
174
}
175
```
176
177
### Unix Socket Support
178
179
Deploy applications using Unix domain sockets for inter-process communication.
180
181
```python { .api }
182
def run_unix_socket(
183
path: str,
184
mode: int = 0o666,
185
**kwargs
186
):
187
"""
188
Run server on Unix domain socket.
189
190
Parameters:
191
- path: Unix socket file path
192
- mode: Socket file permissions
193
194
Benefits:
195
- Lower overhead than TCP sockets
196
- Better security (filesystem permissions)
197
- Ideal for reverse proxy setups
198
"""
199
200
# Configuration for Unix sockets
201
UNIX: str = "/tmp/sanic.sock" # Unix socket path
202
UNIX_MODE: int = 0o666 # Socket file permissions
203
```
204
205
### Server Protocols
206
207
Support for different server protocols and implementations.
208
209
```python { .api }
210
# Built-in protocol classes
211
from sanic.server.protocols.http_protocol import HttpProtocol
212
from sanic.server.protocols.websocket_protocol import WebSocketProtocol
213
214
class CustomHttpProtocol(HttpProtocol):
215
"""Custom HTTP protocol implementation."""
216
217
def __init__(self, *args, **kwargs):
218
super().__init__(*args, **kwargs)
219
# Custom protocol initialization
220
221
async def http_request_handler(self, request):
222
"""Custom request handling logic."""
223
# Custom processing
224
return await super().http_request_handler(request)
225
226
# Use custom protocol
227
app.run(protocol=CustomHttpProtocol)
228
```
229
230
### Process Management
231
232
Server lifecycle management and graceful shutdown handling.
233
234
```python { .api }
235
def stop(self):
236
"""
237
Stop the running server gracefully.
238
239
Features:
240
- Graceful connection closure
241
- Worker process coordination
242
- Resource cleanup
243
- Signal handling
244
"""
245
246
def restart(self, **kwargs):
247
"""
248
Restart the server with new configuration.
249
250
Parameters:
251
- **kwargs: New configuration options
252
253
Features:
254
- Zero-downtime restart capability
255
- Configuration updates
256
- Worker process cycling
257
"""
258
259
# Graceful shutdown configuration
260
GRACEFUL_SHUTDOWN_TIMEOUT: float = 15.0 # Shutdown timeout in seconds
261
KEEP_ALIVE_TIMEOUT: int = 5 # Keep-alive connection timeout
262
REQUEST_TIMEOUT: int = 60 # Request processing timeout
263
RESPONSE_TIMEOUT: int = 60 # Response sending timeout
264
```
265
266
### Development Server Features
267
268
Development-focused server features for rapid development and debugging.
269
270
```python { .api }
271
# Development configuration
272
DEBUG: bool = False # Debug mode
273
AUTO_RELOAD: bool = False # Auto-reload on file changes
274
ACCESS_LOG: bool = True # Enable access logging
275
MOTD: bool = True # Show message of the day
276
LOGO: str = None # Custom logo display
277
278
# Auto-reload functionality
279
def enable_auto_reload(app, reload_dir: str = "."):
280
"""
281
Enable automatic server restart on file changes.
282
283
Parameters:
284
- app: Sanic application instance
285
- reload_dir: Directory to watch for changes
286
287
Features:
288
- File system monitoring
289
- Automatic server restart
290
- Development workflow optimization
291
"""
292
```
293
294
### Production Deployment Patterns
295
296
Recommended patterns and configurations for production environments.
297
298
```python { .api }
299
# Production server configuration
300
production_config = {
301
"host": "0.0.0.0",
302
"port": 8000,
303
"workers": 4, # CPU core count
304
"debug": False,
305
"access_log": True,
306
"auto_reload": False,
307
"backlog": 2048,
308
"keep_alive_timeout": 5,
309
"request_timeout": 60,
310
"response_timeout": 60,
311
"request_max_size": 100 * 1024 * 1024, # 100MB
312
}
313
314
# Load balancer configuration
315
load_balancer_config = {
316
"host": "127.0.0.1", # Bind to localhost
317
"port": 8000,
318
"workers": 8,
319
"backlog": 4096,
320
"forwarded_secret": "your-secret-key",
321
"real_ip_header": "X-Real-IP",
322
"proxies_count": 1,
323
}
324
```
325
326
## Usage Examples
327
328
### Basic Server Deployment
329
330
```python
331
from sanic import Sanic
332
from sanic.response import json
333
334
app = Sanic("ProductionApp")
335
336
@app.route("/health")
337
async def health_check(request):
338
return json({"status": "healthy", "service": "ProductionApp"})
339
340
@app.route("/api/data")
341
async def get_data(request):
342
return json({"data": "production data"})
343
344
if __name__ == "__main__":
345
# Production server configuration
346
app.run(
347
host="0.0.0.0",
348
port=8000,
349
workers=4,
350
debug=False,
351
access_log=True
352
)
353
```
354
355
### SSL/HTTPS Deployment
356
357
```python
358
import ssl
359
from sanic import Sanic
360
361
app = Sanic("SecureApp")
362
363
@app.route("/")
364
async def secure_endpoint(request):
365
return json({
366
"message": "Secure connection established",
367
"scheme": request.scheme,
368
"secure": request.scheme == "https"
369
})
370
371
if __name__ == "__main__":
372
# SSL configuration
373
ssl_config = {
374
"cert": "/etc/ssl/certs/server.crt",
375
"key": "/etc/ssl/private/server.key",
376
"ssl_version": ssl.PROTOCOL_TLS,
377
"ciphers": "ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS"
378
}
379
380
app.run(
381
host="0.0.0.0",
382
port=8443,
383
ssl=ssl_config,
384
workers=4
385
)
386
```
387
388
### Multi-Worker Production Setup
389
390
```python
391
import os
392
import multiprocessing
393
from sanic import Sanic
394
395
app = Sanic("MultiWorkerApp")
396
397
# Production configuration
398
app.config.update({
399
"REQUEST_TIMEOUT": 60,
400
"RESPONSE_TIMEOUT": 60,
401
"KEEP_ALIVE_TIMEOUT": 5,
402
"REQUEST_MAX_SIZE": 100 * 1024 * 1024, # 100MB
403
"GRACEFUL_SHUTDOWN_TIMEOUT": 15.0,
404
})
405
406
@app.before_server_start
407
async def setup_production(app, loop):
408
"""Production setup tasks."""
409
# Initialize database pool
410
app.ctx.db_pool = await create_database_pool()
411
412
# Setup logging
413
setup_production_logging()
414
415
# Initialize cache
416
app.ctx.cache = await create_cache_client()
417
418
@app.before_server_stop
419
async def cleanup_production(app, loop):
420
"""Production cleanup tasks."""
421
if hasattr(app.ctx, 'db_pool'):
422
await app.ctx.db_pool.close()
423
424
if hasattr(app.ctx, 'cache'):
425
await app.ctx.cache.close()
426
427
if __name__ == "__main__":
428
# Calculate optimal worker count
429
worker_count = min(multiprocessing.cpu_count(), int(os.getenv("MAX_WORKERS", 8)))
430
431
app.run(
432
host="0.0.0.0",
433
port=int(os.getenv("PORT", 8000)),
434
workers=worker_count,
435
debug=False,
436
access_log=True,
437
backlog=2048
438
)
439
```
440
441
### Unix Socket Deployment
442
443
```python
444
import os
445
from sanic import Sanic
446
447
app = Sanic("UnixSocketApp")
448
449
@app.route("/status")
450
async def status(request):
451
return json({"status": "running", "socket": "unix"})
452
453
if __name__ == "__main__":
454
socket_path = "/tmp/sanic_app.sock"
455
456
# Remove existing socket file
457
if os.path.exists(socket_path):
458
os.unlink(socket_path)
459
460
# Run on Unix socket
461
app.run(
462
unix=socket_path,
463
workers=4,
464
debug=False
465
)
466
467
# Set socket permissions
468
os.chmod(socket_path, 0o666)
469
```
470
471
### Container Deployment
472
473
```python
474
import signal
475
import sys
476
from sanic import Sanic
477
478
app = Sanic("ContainerApp")
479
480
# Container-friendly configuration
481
app.config.update({
482
"HOST": "0.0.0.0",
483
"PORT": int(os.getenv("PORT", 8000)),
484
"WORKERS": int(os.getenv("WORKERS", 1)),
485
"DEBUG": os.getenv("DEBUG", "false").lower() == "true",
486
"ACCESS_LOG": os.getenv("ACCESS_LOG", "true").lower() == "true",
487
})
488
489
@app.before_server_start
490
async def setup_container(app, loop):
491
"""Container-specific setup."""
492
app.logger.info("Starting application in container")
493
494
# Health check endpoint for container orchestration
495
@app.route("/health")
496
async def health_check(request):
497
return json({"status": "healthy"})
498
499
@app.route("/ready")
500
async def readiness_check(request):
501
# Check dependencies (database, cache, etc.)
502
ready = await check_dependencies()
503
if ready:
504
return json({"status": "ready"})
505
else:
506
return json({"status": "not ready"}, status=503)
507
508
def signal_handler(signum, frame):
509
"""Handle container shutdown signals."""
510
app.logger.info(f"Received signal {signum}, shutting down gracefully")
511
app.stop()
512
513
if __name__ == "__main__":
514
# Register signal handlers for graceful shutdown
515
signal.signal(signal.SIGTERM, signal_handler)
516
signal.signal(signal.SIGINT, signal_handler)
517
518
try:
519
app.run(
520
host=app.config.HOST,
521
port=app.config.PORT,
522
workers=app.config.WORKERS,
523
debug=app.config.DEBUG,
524
access_log=app.config.ACCESS_LOG
525
)
526
except KeyboardInterrupt:
527
app.logger.info("Application stopped by user")
528
sys.exit(0)
529
```
530
531
### Reverse Proxy Configuration
532
533
```python
534
from sanic import Sanic
535
from sanic.response import json
536
537
app = Sanic("ProxiedApp")
538
539
# Configure for reverse proxy setup
540
app.config.update({
541
"FORWARDED_SECRET": os.getenv("FORWARDED_SECRET"),
542
"REAL_IP_HEADER": "X-Real-IP",
543
"PROXIES_COUNT": 1, # Number of proxy layers
544
})
545
546
@app.middleware("request")
547
async def log_real_ip(request):
548
"""Log real client IP from proxy headers."""
549
real_ip = request.ip # Sanic handles proxy headers automatically
550
app.logger.info(f"Request from {real_ip} to {request.path}")
551
552
@app.route("/proxy-info")
553
async def proxy_info(request):
554
"""Display proxy-related information."""
555
return json({
556
"client_ip": request.ip,
557
"forwarded": dict(request.forwarded),
558
"remote_addr": request.remote_addr,
559
"scheme": request.scheme,
560
"host": request.host,
561
"headers": {
562
"x-forwarded-for": request.headers.get("X-Forwarded-For"),
563
"x-forwarded-proto": request.headers.get("X-Forwarded-Proto"),
564
"x-real-ip": request.headers.get("X-Real-IP"),
565
}
566
})
567
568
if __name__ == "__main__":
569
# Run behind reverse proxy (nginx, HAProxy, etc.)
570
app.run(
571
host="127.0.0.1", # Bind to localhost only
572
port=8000,
573
workers=4,
574
debug=False
575
)
576
```
577
578
### Custom Server Protocol
579
580
```python
581
from sanic.server.protocols.http_protocol import HttpProtocol
582
from sanic import Sanic
583
584
class CustomProtocol(HttpProtocol):
585
"""Custom HTTP protocol with request logging."""
586
587
def __init__(self, *args, **kwargs):
588
super().__init__(*args, **kwargs)
589
self.request_count = 0
590
591
async def http_request_handler(self, request):
592
"""Custom request handling with metrics."""
593
self.request_count += 1
594
595
# Add custom headers
596
request.ctx.request_number = self.request_count
597
598
# Log request
599
self.logger.info(f"Processing request #{self.request_count}: {request.method} {request.path}")
600
601
# Call parent handler
602
response = await super().http_request_handler(request)
603
604
# Add custom response headers
605
if response:
606
response.headers["X-Request-Number"] = str(self.request_count)
607
response.headers["X-Server-Protocol"] = "custom"
608
609
return response
610
611
app = Sanic("CustomProtocolApp")
612
613
@app.route("/")
614
async def index(request):
615
return json({
616
"message": "Custom protocol server",
617
"request_number": request.ctx.request_number
618
})
619
620
if __name__ == "__main__":
621
app.run(
622
host="0.0.0.0",
623
port=8000,
624
protocol=CustomProtocol,
625
workers=2
626
)
627
```