Deployment
A Punk application is a PSGI coderef; anything that serves PSGI serves it. It is fastest on Hyperman, the event-loop server it was built against.
Hyperman
hyperman --workers 4 --port 8080 app.psgi
Hyperman gives Punk three things other servers cannot:
- Non-blocking futures - a pending
Punk::Futureparks on the worker's loop and the worker serves other requests meanwhile. - Detached WebSockets -
detachhands the socket to the application, so connections do not pin workers. - The C ABI - Punk speaks to Hyperman through
hm_abi.hdirectly, no PSGI-layer overhead on the hot paths.
HTTPS, and :80 beside :443
Hyperman binds several listeners in one run, each independently plain
or TLS, so an ordinary site needs nothing in front of it:
Hyperman->run(
app => $app,
listen => [
{ port => 80, redirect_https => 443 },
{ port => 443, tls_cert => $cert, tls_key => $key },
],
);
redirect_https answers every request on that listener with a 301
to the same host and path on the https port, in C, before the app is
reached - so the plain port costs a parse and a write, not a dispatch.
This site ships that as a script. bin/punk-site makes a self-signed
certificate on first run and serves both ports:
sudo bin/punk-site # 80 -> 301 -> 443
bin/punk-site --dev # 8080 / 8443, no root
bin/punk-site --cert /etc/letsencrypt/live/you/fullchain.pem \
--key /etc/letsencrypt/live/you/privkey.pem
Two things worth knowing before you point it at the internet:
- Ports below 1024 need root, and Hyperman has no privilege-drop
option, so a root start stays root. Prefer
setcap cap_net_bind_service=+epon the perl binary (Linux), a pf redirect to 8080/8443 (macOS), or a reverse proxy. detachrefuses a TLS socket, so an app withwebsocketorsseroutes cannot serve them from a TLS listener. Terminate TLS in front of it instead - nginx, or the small terminator in Punk'sexample/Chat/bin/tls-proxy- and give Punk plain HTTP/1. That is why the Chat example is arranged the way it is, and why this site (pages, docs and JSON) is not.
Any PSGI server
plackup app.psgi
Everything works; the async paths block politely, and WebSocket routes
need blocking => 1 (over psgix.io) or the app refuses to boot with
routes it cannot serve.
Environments
PUNK_ENV=production hyperman app.psgi
selects the punk.production.yml config layer - see
Config and secrets. Check it resolves
before switching traffic:
PUNK_ENV=production punk config check
Frozen at boot
to_app compiles the whole application - routes, guards, controllers,
templates registered, spec validated, markdown rendered, search indexed.
Two consequences worth planning around:
- Failures are boot failures. A typo'd controller, a missing template engine or an unresolvable secret stops the deploy, not the 3am request.
- Content changes need a restart. A
markdownmount serves frozen bytes; edit the docs, restart the app (in development,reload => 1orpunk devre-renders on change).
Development
punk dev
serves on Hyperman with restart-on-change. punk doctor reports the
environment - Perl, module versions, which C ABIs are live - when a
deployment target misbehaves.
A checklist
punk routes- the table you think you are shippingPUNK_ENV=production punk config check- secrets resolvepunk doctor- ABIs live, versions expectedprove -l t- the app boots and answershyperman --workers N app.psgi