README.caddy_frontend.rst 20.6 KB
Newer Older
1 2 3
==============
Caddy Frontend
==============
4

5
Frontend system using Caddy, based on apache-frontend software release, allowing to rewrite and proxy URLs like myinstance.myfrontenddomainname.com to real IP/URL of myinstance.
6

7
Caddy Frontend works using the master instance / slave instance design.  It means that a single main instance of Caddy will be used to act as frontend for many slaves.
8 9 10 11

Software type
=============

12 13 14 15 16
Caddy frontend is available in 4 software types:
  * ``default`` : The standard way to use the Caddy frontend configuring everything with a few given parameters
  * ``custom-personal`` : This software type allow each slave to edit its Caddy configuration file
  * ``default-slave`` : XXX
  * ``custom-personal-slave`` : XXX
17 18 19


About frontend replication
20 21 22
==========================

Slaves of the root instance are sent as a parameter to requested frontends which will process them. The only difference is that they will then return the would-be published information to the root instance instead of publishing it. The root instance will then do a synthesis and publish the information to its slaves. The replicate instance only use 5 type of parameters for itself and will transmit the rest to requested frontends.
23 24

These parameters are :
25 26 27 28 29 30 31 32

  * ``-frontend-type`` : the type to deploy frontends with. (default to 2)
  * ``-frontend-quantity`` : The quantity of frontends to request (default to "default")
  * ``-frontend-i-state``: The state of frontend i
  * ``-frontend-config-i-foo``: Frontend i will be requested with parameter foo
  * ``-frontend-software-release-url``: Software release to be used for frontends, default to the current software release
  * ``-sla-i-foo`` : where "i" is the number of the concerned frontend (between 1 and "-frontend-quantity") and "foo" a sla parameter.

33
for example::
34 35 36 37 38 39 40 41 42 43 44 45 46

  <parameter id="-frontend-quantity">3</parameter>
  <parameter id="-frontend-type">custom-personal</parameter>
  <parameter id="-frontend-2-state">stopped</parameter>
  <parameter id="-sla-3-computer_guid">COMP-1234</parameter>
  <parameter id="-frontend-software-release-url">https://lab.nexedi.com/nexedi/slapos/raw/someid/software/caddy-frontend/software.cfg</parameter>


will request the third frontend on COMP-1234. All frontends will be of software type ``custom-personal``. The second frontend will be requested with the state stopped

*Note*: the way slaves are transformed to a parameter avoid modifying more than 3 lines in the frontend logic.

**Important NOTE**: The way you ask for slave to a replicate frontend is the same as the one you would use for the software given in "-frontend-quantity". Do not forget to use "replicate" for software type. XXXXX So far it is not possible to do a simple request on a replicate frontend if you do not know the software_guid or other sla-parameter of the master instance. In fact we do not know yet the software type of the "requested" frontends. TO BE IMPLEMENTED
47 48 49

XXX Should be moved to specific JSON File

50 51 52 53
Extra-parameter per frontend with default::

  ram-cache-size = 1G
  disk-cache-size = 8G
54 55 56 57

How to deploy a frontend server
===============================

58 59 60
This is to deploy an entire frontend server with a public IPv4.  If you want to use an already deployed frontend to make your service available via ipv4, switch to the "Example" parts.

First, you will need to request a "master" instance of Caddy Frontend with:
61

62 63
  * A ``domain`` parameter where the frontend will be available
  * A ``public-ipv4`` parameter to state which public IPv4 will be used
64 65

like::
66

67 68 69 70 71 72
  <?xml version='1.0' encoding='utf-8'?>
  <instance>
   <parameter id="domain">moulefrite.org</parameter>
   <parameter id="public-ipv4">xxx.xxx.xxx.xxx</parameter>
  </instance>

73 74
Then, it is possible to request many slave instances (currently only from slapconsole, UI doesn't work yet) of Caddy Frontend, like::

75
  instance = request(
76
    software_release=caddy_frontend,
77 78 79 80 81
    partition_reference='frontend2',
    shared=True,
    partition_parameter_kw={"url":"https://[1:2:3:4]:1234/someresource"}
  )

82 83 84
Those slave instances will be redirected to the "master" instance, and you will see on the "master" instance the associated proper directives of all slave instances.

Finally, the slave instance will be accessible from: https://someidentifier.moulefrite.org.
85

86 87
About SSL and SlapOS Master Zero Knowledge
==========================================
88 89 90

**IMPORTANT**: One Caddy can not serve more than one specific SSL site and be compatible with obsolete browser (i.e.: IE8). See http://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI

91 92
SSL keys and certificates are directly send to the frontend cluster in order to follow zero knowledge principle of SlapOS Master.

93 94
*Note*: Until master partition or slave specific certificate is uploaded each slave is served with fallback certificate.  This fallback certificate is self signed, does not match served hostname and results with lack of response on HTTPs.

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
Master partition
----------------

After requesting master partition it will return ``master-key-generate-auth-url`` and ``master-key-upload-url``.

Doing HTTP GET on ``master-key-generate-auth-url`` will return authentication token, which is used to communicate with ``master-key-upload-url``. This token shall be stored securely.

By doing HTTP PUT to ``master-key-upload-url`` with appended authentication token it is possible to upload PEM bundle of certificate, key and any accompanying CA certificates to the master.

Example sessions is::

  request(...)

  curl -X GET master-key-generate-auth-url
  > authtoken

  cat certificate.pem key.pem ca-bundle.pem > master.pem

  curl -X PUT --data-binary @master.pem master-key-upload-url+authtoken

This replaces old request parameters:

 * ``apache-certificate``
 * ``apache-key``
 * ``apache-ca-certificate``

(*Note*: They are still supported for backward compatibility, but any value send to the ``master-key-upload-url`` will supersede information from SlapOS Master.)

Slave partition
---------------

After requesting slave partition it will return ``key-generate-auth-url`` and ``key-upload-url``.

Doing HTTP GET on ``key-generate-auth-url`` will return authentication token, which is used to communicate with ``key-upload-url``. This token shall be stored securely.

By doing HTTP PUT to ``key-upload-url`` with appended authentication token it is possible to upload PEM bundle of certificate, key and any accompanying CA certificates to the master.

Example sessions is::

  request(...)

  curl -X GET key-generate-auth-url
  > authtoken

  cat certificate.pem key.pem ca-bundle.pem > master.pem

  curl -X PUT --data-binary @master.pem key-upload-url+authtoken

This replaces old request parameters:

 * ``ssl_crt``
 * ``ssl_key``
 * ``ssl_ca_crt``

(*Note*: They are still supported for backward compatibility, but any value send to the ``key-upload-url`` will supersede information from SlapOS Master.)


152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
How to have custom configuration in frontend server - XXX - to be written
=========================================================================

In your instance directory, you, as sysadmin, can directly edit two
configuration files that won't be overwritten by SlapOS to customize your
instance:

 * ``$PARTITION_PATH/srv/srv/apache-conf.d/apache_frontend.custom.conf``
 * ``$PARTITION_PATH/srv/srv/apache-conf.d/apache_frontend.virtualhost.custom.conf``

The first one is included in the end of the main apache configuration file.
The second one is included in the virtualhost of the main apache configuration file.

SlapOS will just create those two files for you, then completely forget them.

*Note*: make sure that the UNIX user of the instance has read access to those
files if you edit them.
169 170 171 172 173 174 175

Instance Parameters
===================

Master Instance Parameters
--------------------------

176
The parameters for instances are described at `instance-caddy-input-schema.json <instance-caddy-input-schema.json>`_.
177 178 179 180 181

Here some additional informations about the parameters listed, below:

domain
~~~~~~
182 183 184

Name of the domain to be used (example: mydomain.com). Sub domains of this domain will be used for the slave instances (example: instance12345.mydomain.com). It is then recommended to add a wild card in DNS for the sub domains of the chosen domain like::

185
  *.mydomain.com. IN A 123.123.123.123
186 187

Using the IP given by the Master Instance.  "domain" is a mandatory Parameter.
188 189 190

public-ipv4
~~~~~~~~~~~
191
Public ipv4 of the frontend (the one Caddy will be indirectly listening to)
192 193 194

port
~~~~
195
Port used by Caddy. Optional parameter, defaults to 4443.
196 197 198

plain_http_port
~~~~~~~~~~~~~~~
199
Port used by Caddy to serve plain http (only used to redirect to https).
200 201 202 203 204 205
Optional parameter, defaults to 8080.


Slave Instance Parameters
-------------------------

206
The parameters for instances are described at `instance-slave-caddy-input-schema.json <instance-slave-caddy-input-schema.json>`_.
207 208 209 210 211 212 213

Here some additional informations about the parameters listed, below:

path
~~~~
Only used if type is "zope".

214
Will append the specified path to the "VirtualHostRoot" of the zope's VirtualHostMonster.
215 216 217 218

"path" is an optional parameter, ignored if not specified.
Example of value: "/erp5/web_site_module/hosting/"

219 220
caddy_custom_https
~~~~~~~~~~~~~~~~~~
221
Raw Caddy configuration in python template format (i.e. write "%%" for one "%") for the slave listening to the https port. Its content will be templatified in order to access functionalities such as cache access, ssl certificates... The list is available above.
222

223 224
*Note*: The system will reject slaves which does not pass validation of caddy configuration, despite them being in ``-frontend-authorized-slave-string``, as otherwise this will lead to the whole frontend to fail.

225 226
caddy_custom_http
~~~~~~~~~~~~~~~~~
227
Raw Caddy configuration in python template format (i.e. write "%%" for one "%") for the slave listening to the http port. Its content will be templatified in order to access functionalities such as cache access, ssl certificates... The list is available above
228

229 230
*Note*: The system will reject slaves which does not pass validation of caddy configuration, despite them being in ``-frontend-authorized-slave-string``, as otherwise this will lead to the whole frontend to fail.

231 232
url
~~~
233 234 235 236
Necessary to activate cache. ``url`` of backend to use.

``url`` is an optional parameter.

237 238 239 240
Example: http://mybackend.com/myresource

domain
~~~~~~
241 242 243 244 245 246 247

Necessary to activate cache.

The frontend will be accessible from this domain.

``domain`` is an optional parameter.

248 249 250 251
Example: www.mycustomdomain.com

enable_cache
~~~~~~~~~~~~
252 253 254 255

Necessary to activate cache.

``enable_cache`` is an optional parameter.
256

257 258 259 260 261 262 263 264
Functionalities for Caddy configuration
---------------------------------------

In the slave Caddy configuration you can use parameters that will be replaced during instantiation. They should be entered as python templates parameters ex: ``%(parameter)s``:

  * ``cache_access`` : url of the cache. Should replace backend url in configuration to use the cache
  * ``access_log`` : path of the slave error log in order to log in a file.
  * ``error_log`` : path of the slave access log in order to log in a file.
265
  * ``certificate`` : path to the certificate
266 267 268 269 270


Examples
========

271
Here are some example of how to make your SlapOS service available through an already deployed frontend.
272 273 274 275 276 277

Simple Example (default)
------------------------

Request slave frontend instance so that https://[1:2:3:4:5:6:7:8]:1234 will be
redirected and accessible from the proxy::
278

279
  instance = request(
280
    software_release=caddy_frontend,
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    software_type="RootSoftwareInstance",
    partition_reference='my frontend',
    shared=True,
    partition_parameter_kw={
        "url":"https://[1:2:3:4:5:6:7:8]:1234",
    }
  )


Zope Example (default)
----------------------

Request slave frontend instance using a Zope backend so that
https://[1:2:3:4:5:6:7:8]:1234 will be redirected and accessible from the
proxy::
296

297
  instance = request(
298
    software_release=caddy_frontend,
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
    software_type="RootSoftwareInstance",
    partition_reference='my frontend',
    shared=True,
    partition_parameter_kw={
        "url":"https://[1:2:3:4:5:6:7:8]:1234",
        "type":"zope",
    }
  )


Advanced example 
-----------------

Request slave frontend instance using a Zope backend, with Varnish activated,
listening to a custom domain and redirecting to /erp5/ so that
https://[1:2:3:4:5:6:7:8]:1234/erp5/ will be redirected and accessible from
the proxy::
316

317
  instance = request(
318
    software_release=caddy_frontend,
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
    software_type="RootSoftwareInstance",
    partition_reference='my frontend',
    shared=True,
    partition_parameter_kw={
        "url":"https://[1:2:3:4:5:6:7:8]:1234",
        "enable_cache":"true",
        "type":"zope",
        "path":"/erp5",
        "domain":"mycustomdomain.com",
    }
  )

Simple Example 
---------------

334 335
Request slave frontend instance so that https://[1:2:3:4:5:6:7:8]:1234 will be::

336
  instance = request(
337
    software_release=caddy_frontend,
338 339 340 341 342 343 344
    software_type="RootSoftwareInstance",
    partition_reference='my frontend',
    shared=True,
    software_type="custom-personal",
    partition_parameter_kw={
        "url":"https://[1:2:3:4:5:6:7:8]:1234",

345
        "caddy_custom_https":'
346 347
  https://www.example.com:%(https_port)s, https://example.com:%(https_port)s {
    bind %(local_ipv4)s
348
    tls %%(certificate)s %%(certificate)s
349

350 351 352 353 354 355 356 357 358
    log / %(access_log)s {combined}
    errors %(error_log)s

    proxy / https://[1:2:3:4:5:6:7:8]:1234 {
      transparent
      timeout 600s
      insecure_skip_verify
    }
  }
359
        "caddy_custom_http":'
360 361 362 363 364 365 366 367 368
  http://www.example.com:%(http_port)s, http://example.com:%(http_port)s {
    bind %(local_ipv4)s
    log / %(access_log)s {combined}
    errors %(error_log)s
  
    proxy / https://[1:2:3:4:5:6:7:8]:1234/ {
      transparent
      timeout 600s
      insecure_skip_verify
369
    }
370
  }
371

372 373 374 375
Simple Cache Example - XXX - to be written
------------------------------------------

Request slave frontend instance so that https://[1:2:3:4:5:6:7:8]:1234 will be::
376 377

  instance = request(
378
    software_release=caddy_frontend,
379 380 381 382 383 384 385 386 387
    software_type="RootSoftwareInstance",
    partition_reference='my frontend',
    shared=True,
    software_type="custom-personal",
    partition_parameter_kw={
        "url":"https://[1:2:3:4:5:6:7:8]:1234",
	"domain": "www.example.org",
	"enable_cache": "True",

388
        "caddy_custom_https":'
389 390 391 392 393 394 395 396 397 398 399 400 401
  ServerName www.example.org
  ServerAlias www.example.org
  ServerAlias example.org
  ServerAdmin geronimo@example.org
  SSLEngine on
  SSLProxyEngine on
  # Rewrite part
  ProxyVia On
  ProxyPreserveHost On
  ProxyTimeout 600
  RewriteEngine On
  RewriteRule ^/(.*) %(cache_access)s/$1 [L,P]',

402
        "caddy_custom_http":'
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
  ServerName www.example.org
  ServerAlias www.example.org
  ServerAlias example.org
  ServerAdmin geronimo@example.org
  SSLProxyEngine on
  # Rewrite part
  ProxyVia On
  ProxyPreserveHost On
  ProxyTimeout 600
  RewriteEngine On

  # Not using HTTPS? Ask that guy over there.
  # Dummy redirection to https. Note: will work only if https listens
  # on standard port (443).
  RewriteRule ^/(.*) %(cache_access)s/$1 [L,P],
    }
  )


422 423
Advanced example - XXX - to be written
--------------------------------------
424 425

Request slave frontend instance using custom apache configuration, willing to use cache and ssl certificates.
426
Listening to a custom domain and redirecting to /erp5/ so that
427 428
https://[1:2:3:4:5:6:7:8]:1234/erp5/ will be redirected and accessible from
the proxy::
429

430
  instance = request(
431
    software_release=caddy_frontend,
432 433 434 435 436 437 438 439 440 441 442
    software_type="RootSoftwareInstance",
    partition_reference='my frontend',
    shared=True,
    software_type="custom-personal",
    partition_parameter_kw={
        "url":"https://[1:2:3:4:5:6:7:8]:1234",
        "enable_cache":"true",
        "type":"zope",
        "path":"/erp5",
        "domain":"example.org",

443
  	"caddy_custom_https":'
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
  ServerName www.example.org
  ServerAlias www.example.org
  ServerAdmin example.org
  SSLEngine on
  SSLProxyEngine on
  SSLProtocol all -SSLv2 -SSLv3
  SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:HIGH:!aNULL:!MD5
  SSLHonorCipherOrder on
  # Use personal ssl certificates
  SSLCertificateFile %(ssl_crt)s
  SSLCertificateKeyFile %(ssl_key)s
  SSLCACertificateFile %(ssl_ca_crt)s
  SSLCertificateChainFile %(ssl_ca_crt)s
  # Configure personal logs
  ErrorLog "%(error_log)s"
  LogLevel info
  LogFormat "%%h %%l %%{REMOTE_USER}i %%t \"%%r\" %%>s %%b \"%%{Referer}i\" \"%%{User-Agent}i\" %%D" combined
  CustomLog "%(access_log)s" combined
  # Rewrite part
  ProxyVia On
  ProxyPreserveHost On
  ProxyTimeout 600
  RewriteEngine On
  # Redirect / to /index.html
  RewriteRule ^/$ /index.html [R=302,L]
  # Use cache
  RewriteRule ^/(.*) %(cache_access)s/VirtualHostBase/https/www.example.org:443/erp5/VirtualHostRoot/$1 [L,P]',

472
    "caddy_custom_http":'
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
  ServerName www.example.org
  ServerAlias www.example.org
  ServerAlias example.org
  ServerAdmin geronimo@example.org
  SSLProxyEngine on
  # Rewrite part
  ProxyVia On
  ProxyPreserveHost On
  ProxyTimeout 600
  RewriteEngine On
  # Configure personal logs
  ErrorLog "%(error_log)s"
  LogLevel info
  LogFormat "%%h %%l %%{REMOTE_USER}i %%t \"%%r\" %%>s %%b \"%%{Referer}i\" \"%%{User-Agent}i\" %%D" combined
  CustomLog "%(access_log)s" combined
  # Not using HTTPS? Ask that guy over there.
  # Dummy redirection to https. Note: will work only if https listens
  # on standard port (443).
  RewriteRule ^/(.*)$ https://%%{SERVER_NAME}%%{REQUEST_URI}',

    "ssl_key":"-----BEGIN RSA PRIVATE KEY-----
494 495 496 497 498 499 500 501 502 503 504
  XXXXXXX..........XXXXXXXXXXXXXXX
  -----END RSA PRIVATE KEY-----",
      "ssl_crt":'-----BEGIN CERTIFICATE-----
  XXXXXXXXXXX.............XXXXXXXXXXXXXXXXXXX
  -----END CERTIFICATE-----',
      "ssl_ca_crt":'-----BEGIN CERTIFICATE-----
  XXXXXXXXX...........XXXXXXXXXXXXXXXXX
  -----END CERTIFICATE-----',
      "ssl_csr":'-----BEGIN CERTIFICATE REQUEST-----
  XXXXXXXXXXXXXXX.............XXXXXXXXXXXXXXXXXX
  -----END CERTIFICATE REQUEST-----',
505 506 507
    }
  )

Łukasz Nowak's avatar
Łukasz Nowak committed
508 509 510
QUIC Protocol
=============

511
Note: QUIC support in Caddy is really experimental. It can result with silently having problems with QUIC connections or hanging Caddy process. So in case of QUIC error ``QUIC_NETWORK_IDLE_TIMEOUT`` or ``QUIC_PEER_GOING_AWAY`` it is required to restart caddy process.
Łukasz Nowak's avatar
Łukasz Nowak committed
512

513 514
Note: Chrome will refuse to connect to QUIC on different port then HTTPS has been served. As Caddy binds to high ports, if QUIC is wanted, the browser need to connect to high port too.

515
Experimental QUIC available in Caddy is not configurable. If caddy is configured to bind to HTTPS port ``${port}``, QUIC is going to be advertised on this port only. It is not possible to configure another public port in case of port rewriting.
Łukasz Nowak's avatar
Łukasz Nowak committed
516

517 518 519
So it is required to ``DNAT`` from ``${public IP}`` of the computer to the computer partition running caddy ``${local IP}`` with configured port::

  iptables -A DNAT -d ${public IP}/32 -p udp -m udp --dport ${port} -j DNAT --to-destination ${local IP}:${port}
Łukasz Nowak's avatar
Łukasz Nowak committed
520 521


522 523 524 525 526 527 528 529 530 531 532 533
Promises
========

Note that in some cases promises will fail:

 * not possible to request frontend slave for monitoring (monitoring frontend promise)
 * no slaves present (configuration promise and others)
 * no cached slave present (configuration promise and others)
 * no nginx style slave present (websocket, notebook) (configuration promise and others)

This is known issue and shall be tackled soon.

534 535 536 537 538 539 540
KeDiFa
======

Additional partition with KeDiFa (Key Distribution Facility) is by default requested on the same computer as master frontend partition.

By adding to the request keys like ``-sla-kedifa-<key>`` it is possible to provide SLA information for kedifa partition. Eg to put it on computer ``couscous`` it shall be ``-sla-kedifa-computer_guid: couscous``.

541 542 543 544 545 546 547 548 549 550
Notes
=====

It is not possible with slapos to listen to port <= 1024, because process are
not run as root.

Solution 1 (IPv4 only)
----------------------

It is a good idea then to go on the node where the instance is
551
and set some ``iptables`` rules like (if using default ports)::
552 553 554 555

  iptables -t nat -A PREROUTING -p tcp -d {public_ipv4} --dport 443 -j DNAT --to-destination {listening_ipv4}:4443
  iptables -t nat -A PREROUTING -p tcp -d {public_ipv4} --dport 80 -j DNAT --to-destination {listening_ipv4}:8080

556
Where ``{public ip}`` is the public IP of your server, or at least the LAN IP to where your NAT will forward to, and ``{listening ip}`` is the private ipv4 (like 10.0.34.123) that the instance is using and sending as connection parameter.
557 558 559 560

Solution 2 (IPv6 only)
----------------------

561
It is also possible to directly allow the service to listen on 80 and 443 ports using the following command::
562

563
  setcap 'cap_net_bind_service=+ep' /opt/slapgrid/$CADDY_FRONTEND_SOFTWARE_RELEASE_MD5/go.work/bin/caddy
564

565
Then specify in the instance parameters ``port`` and ``plain_http_port`` to be ``443`` and ``80``, respectively.