or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

blueprints.mdconfiguration.mdcore-application.mdexceptions.mdindex.mdmiddleware-signals.mdrequest-response.mdserver-deployment.mdwebsockets.md

server-deployment.mddocs/

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

```