apache2 #2
Description
The Apache Software Foundation's goal is to build a secure, efficient and extensible HTTP server as standards-compliant open source software. The result has long been the number one web server on the Internet. It features support for HTTPS, virtual hosting, CGI, SSI, IPv6, easy scripting and database integration, request/response filtering, many flexible authentication schemes, and more.
- Tags:
- app-servers ›
Juju charm for Apache
The Apache Software Foundation's goal is to build a secure, efficient and extensible HTTP server as standards-compliant open source software. The result has long been the number one web server on the Internet. It features support for HTTPS, virtual hosting, CGI, SSI, IPv6, easy scripting and database integration, request/response filtering, many flexible authentication schemes, and more.
Development
The following steps are needed for testing and development of the charm, but not for deployment:
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:chrisjohnston/flake8
sudo apt-get update
sudo apt-get install python-flake8 python-nose python-coverage \
python-testtools python-pyasn1 python-pyasn1-modules
To fetch additional source dependencies and run the tests:
make build
... will run the unit tests, run flake8 over the source to warn about formatting issues and output a code coverage summary of the 'hooks.py' module.
How to deploy the charm
Assuming you have a copy of the charm into a charms/$distrocodename/apache2
directory relative to your current directory.
... then to perform a deployment execute the following steps:
juju deploy --repository=charms local:apache2
juju set apache2 "vhost_http_template=$(base64 < http_vhost.tmpl)"
# and / or
juju set apache2 "vhost_https_template=$(base64 < https_vhost.tmpl)"
If you want a simple reverseproxy
relation to your services (only
really useful if you have a single unit on the other side of the
relation):
juju add-relation apache2:reverseproxy haproxy:website
# and / or
juju add-relation apache2:reverseproxy squid-reverseproxy:cached-website
Alternatively, you can use the balancer
relation so that requests
are load balanced across multiple units of your services. For more information see the section on Using the balancer relation
:
juju add-relation apache2:balancer haproxy:website
# and / or
juju add-relation apache2:balancer squid-reverseproxy:cached-website
VirtualHost templates
The charm expects a jinja2 template to be passed in. The variables in the template should relate to the services that apache will be proxying -- obviously no variables need to be specified if no proxying is needed.
Virtual host templates can also be specified via relation. See the vhost-config relation section below for more information.
The vhost_template_vars config allows for further customisation of the vhost templates. For example, you can have a single template for a particular service, but use vhost_template_vars to customise it slightly for devel/staging/production environments.
Using the reverseproxy relation
The charm will create the service variable, with the unit_name
,
when the reverseproxy
relationship is joined and present this to
the template at which point the vhost will be generated from the
template again. All config settings are also available to the
template.
For example to access squid then the {{ squid }}
variable should
be used. This will be populated with the hostname:port of the squid
service. The individual hostname and port can also be accessed via
squid_hostname
and squid_port
.
Note: The service name should be used, not the charm name. If deploying a charm with a different service name, use that instead.
The joining charm may set an all_services
variable which
contains a list of services it provides in yaml format (list of
associative arrays):
# ... in haproxy charm, website-relation-joined
relation-set all_services="
- {service_name: gunicorn, service_port: 80}
- {service_name: solr, service_port: 8080}
- {service_name: my-webapp, service_port: 9090}
"
then variables for each service would be available to the jinja2
template in <juju_service_name>_<sub_service_name>
. In our example
above haproxy contains stanzas named gunicorn, solr and my-webapp.
These are accessed as {{ haproxy_gunicorn }}
, {{ haproxy_solr }}
and
{{ haproxy_mywebapp }}
respectively. If any unsupported characters
are in your juju service name or the service names exposed through
"all_services", they will be stripped.
For example a vhost that will pass all traffic on to an haproxy instance:
<VirtualHost *:80>
ServerName radiotiptop.org.uk
CustomLog /var/log/apache2/radiotiptop-access.log combined
ErrorLog /var/log/apache2/radiotiptop-error.log
DocumentRoot /srv/radiotiptop/www/root
ProxyRequests off
<Proxy *>
Order Allow,Deny
Allow from All
ErrorDocument 403 /offline.html
ErrorDocument 500 /offline.html
ErrorDocument 502 /offline.html
ErrorDocument 503 /offline.html
</Proxy>
ProxyPreserveHost off
ProxyPassReverse / http://{{ haproxy_gunicorn }}/
RewriteEngine on
RewriteRule ^/$ /index.html [L]
RewriteRule ^/(.*)$ http://{{ haproxy_gunicorn }}/$1 [P,L]
</VirtualHost>
Using the balancer
relation
Using the balancer relation will set up named balancers using
Apache's mod_balancer. Each balancer will be named after the
sitenames
or all_services
setting exported from the other side
of the relation. Requests sent through those balancers will have a
X-Balancer-Name
header set, which can be used by the related
service to appropriatedly route requests internally.
The joining charm may set an all_services
variable which
contains a list of services it provides in yaml format (list of
associative arrays):
# ... in haproxy charm, website-relation-joined
relation-set all_services="
- {service_name: gunicorn, service_port: 80}
- {service_name: solr, service_port: 8080}
- {service_name: my-webapp, service_port: 9090}
"
Each separate service name will cause a new balancer
definition to be created on the Apache side, like:
For example a vhost that will pass specific requests to the gunicorn
service that's defined in haproxy:
<VirtualHost *:80>
ServerName radiotiptop.org.uk
CustomLog /var/log/apache2/radiotiptop-access.log combined
ErrorLog /var/log/apache2/radiotiptop-error.log
DocumentRoot /srv/radiotiptop/www/root
ProxyRequests off
<Proxy *>
Order Allow,Deny
Allow from All
ErrorDocument 403 /offline.html
ErrorDocument 500 /offline.html
ErrorDocument 502 /offline.html
ErrorDocument 503 /offline.html
</Proxy>
ProxyPreserveHost on
RewriteEngine on
RewriteRule ^/$ /index.html [L]
RewriteRule ^/(.*)$ balancer://gunicorn/$1 [P,L]
</VirtualHost>
Using the vhost-config relation
The nice thing about this relation, is as long as a charm support it, deploying apache as a front-end for a web service should be as simple as establishing the relation. If you need more details for how to implement this, read on.
The template files themselves can be specified via this relation. This makes
deployment of your infrastructure simpler, since users no longer need to
specify a vhosts config option when using apache2 (though they still can). A
candidate charm should provide a relation on the apache-vhost-config
interface. This charm should simply set the following data when relating:
relation-set vhosts="- {port: '443', template: dGVtcGxhdGU=}\n- {port: '80', template: dGVtcGxhdGU=}\n"
Notice the vhosts
definition is in yaml, the format is simple. vhosts
should contain a yaml encoded data structure of a list of key value hashes, or
dictionaries. In each dictionary, port
should be set to the port this vhost
should listen on, template
should be set to the base64 encoded template file.
You can include as many of these dictionaries as you would like. If you have
colliding port numbers across your juju infrastructure, the results will be a
bit unpredictable.
For example, if using python for your relating charm, the code to generate a
yaml_string for a vhost on port 80
would be similar to this:
import yaml
import base64
template = get_template()
vhosts = [{"port": "80", "template": base64.b64encode(template)}]
yaml_string = yaml.dump(vhosts)
Note, that if you are opening a non-standard port (80 and 443 are opened and
understood by the default install of apache2 in Ubuntu) you will need to
instruct Apache to Listen
on that port in your vhost file. Something like the
following will work in your vhost template:
Listen 8080
<VirtualHost *:8080>
...
</VirtualHost>
Relation settings that apache2 provides
When your charm relates it will be provided with the following:
-
servername
- The Apache2 servername. This is typically needed by web applications so they know how to write URLs. -
ssl_cert
- If you asked for a selfsigned certificate, that cert will be available in this setting as a base64 encoded string.
Using the apache-website relation
The apache-website relation provides a very flexible way of configuring an Apache2 website, using subordinate charms. It can support reverse proxies, static websites, and probably many other forms.
To support this relation, a charm must set
-
domain
- The fully-qualified domain name of the site. -
enabled
- Must be set to 'true' when the web site is ready to be used. -
site_config
- A vhost configuration block. -
site_modules
- A list of modules required by the site. If any of these appear indisable_modules
, the site will not be enabled. Otherwise, any required modules will be loaded. -
ports
- A space-separated list of ports that the site uses.
Using the logs relation
The logs relation is for use with a logging subordinate charm. The beaver subordinate can be deployed and related to apache and logstash. Beaver will tail apache logs and send the logs to logstash.
Certs, keys and chains
ssl_keylocation
, ssl_certlocation
and ssl_chainlocation
are
file names in the charm /data
directory. If found, they will be
copied as follows:
- /etc/ssl/private/
- /etc/ssl/certs/
- /etc/ssl/certs/
ssl_key
and ssl_cert
can also be specified which are are assumed
to be base64 encoded. If specified, they will be written to
appropriate directories given the values in ssl_keylocation and
ssl_certlocation as listed above.
ssl_cert
may also be set to SELFSIGNED, which will generate a
certificate. This, of course, is mostly useful for testing and
staging purposes. The generated certifcate/key will be placed
according to ssl_certlocation
and ssl_keylocation
as listed
above.
ssl_protocol
, ssl_honor_cipher_order
, and ssl_cipher_suite
can
be used to override SSL/TLS version and the cipher suites supported.
These default to what Canonical IS recommends and is using. Before
making any changes, please see the Mozilla Security/Server Side TLS.
{enable,disable}_modules
Space separated list of modules to be enabled or disabled. If a module to be enabled cannot be found then the charm will attempt to install it.
OpenId
The openid_provider option takes a comma seperated list of OpenID providers and places them in /etc/apache2/security/allowed-ops.txt. That file can then be refernced by the allowed-op-list-url option when using apache_openid
TODO:
-
Document the use of balancer, nrpe, logging and website-cache
-
Method to deliver site content. This maybe by converting the charm to a subordinate and making it the master charms problem
-
Implement secure method for delivering key. Juju will likely need to provide this.
-
Tuning. No tuning options are present. Convert apache2.conf to a template and expose config options
-
The all_services variable can be passed as part of the http interface and is optional. However its kind of secret and it would be more obvious if a seperate interface was used like http-allservices.
Configuration
- apt-key-id
- (string) A PGP key id. This is used with PPA and the source option to import a PGP public key for verifying repository signatures. This value must match the PPA for apt-source.
- apt-source
- (string) From where to install packages. This is the PPA source line. Note that due to a bug in software-properties add-apt-repository cannot add the ondrej/apache2 ppa, so the default value here is a full sources line.
- config_change_command
- (string) The command to run whenever config has changed. Accepted values are "reload" or "restart" - any other value will mean neither is executed after a config change (which may be desired, if you're running a production server and would rather handle these out of band). Note: some variables like the mpm settings require a restart to go into effect.
- reload
- disable_modules
- (string) List of modules to disable
- status autoindex
- enable_modules
- (string) List of modules to enable
- extra_packages
- (string) List of extra packages to be installed (e.g. commercial GeoIP package)
- lb_balancer_timeout
- (int) How long the backends in mod_proxy_balancer will timeout, in seconds
- 60
- logrotate_count
- (int) The number of days we want to retain logs for
- 365
- logrotate_dateext
- (boolean) Use daily extension like YYYMMDD instead of simply adding a number
- True
- logrotate_rotate
- (string) daily, weekly, monthly, or yearly?
- daily
- mpm_maxclients
- (int) Add desc
- 2048
- mpm_maxrequestsperchild
- (int) Add desc
- mpm_maxsparethreads
- (int) Add desc
- 75
- mpm_minsparethreads
- (int) Add desc
- 25
- mpm_serverlimit
- (int) Add desc
- 128
- mpm_startservers
- (int) Add desc
- 2
- mpm_threadlimit
- (int) Add desc
- 64
- mpm_threadsperchild
- (int) Add desc
- 64
- mpm_type
- (string) worker or prefork
- worker
- nagios_check_http_params
- (string) The parameters to pass to the nrpe plugin check_http.
- nagios_context
- (string) Used by the nrpe-external-master subordinate charm. A string that will be prepended to instance name to set the host name in nagios. So for instance the hostname would be something like: juju-postgresql-0 If you're running multiple environments with the same services in them this allows you to differentiate between them.
- juju
- nagios_servicegroups
- (string) A comma-separated list of nagios servicegroups. If left empty, the nagios_context will be used as the servicegroup
- openid_provider
- (string) Comma seperated list of OpenID providers for authentication.
- package_status
- (string) The status of service-affecting packages will be set to this value in the dpkg database. Useful valid values are "install" and "hold".
- install
- server_signature
- (string) Security setting. Set to one of On Off EMail
- On
- server_tokens
- (string) Security setting. Set to one of Full OS Minimal Minor Major Prod
- OS
- servername
- (string) ServerName for vhost, defaults to the units public-address
- ssl_cert
- (string) base64 encoded server certificate. If the keyword 'SELFSIGNED' is used, the certificate and key will be autogenerated as self-signed.
- ssl_certlocation
- (string) Name and location of ssl certificate in charm/data directory. If not found, will ignore. Basename of this file will be used as the basename of the cert rooted at /etc/ssl/certs. Can be used in conjunction with the ssl_cert parameter to specify the cert as a configuration setting.
- ssl_chain
- (string) base64 encoded chain certificates file. If ssl_cert is specified as SELFSIGNED, this will be ignored.
- ssl_chainlocation
- (string) Name and location of the ssl chain file. Basename of this file will be used as the basename of the chain file rooted at /etc/ssl/certs.
- ssl_cipher_suite
- (string) List of server cipher suites.
- EECDH+AESGCM+AES128:EDH+AESGCM+AES128:EECDH+AES128:EDH+AES128:ECDH+AESGCM+AES128:aRSA+AESGCM+AES128:ECDH+AES128:DH+AES128:aRSA+AES128:EECDH+AESGCM:EDH+AESGCM:EECDH:EDH:ECDH+AESGCM:aRSA+AESGCM:ECDH:DH:aRSA:HIGH:!MEDIUM:!aNULL:!NULL:!LOW:!3DES:!DSS:!EXP:!PSK:!SRP
- ssl_honor_cipher_order
- (string) Enable server cipher suite preference.
- On
- ssl_key
- (string) base64 encoded server certificate key. If ssl_cert is specified as SELFSIGNED, this will be ignored.
- ssl_keylocation
- (string) Name and location of ssl keyfile in charm/data directory. If not found, will ignore. Basename of this file will be used as the basename of the key rooted at /etc/ssl/private. Can be used in conjuntion with the ssl_key parameter to specify the key as a configuration setting.
- ssl_protocol
- (string) SSL Protocols to enable.
- ALL -SSLv2 -SSLv3
- trace_enabled
- (string) Security setting. Set to one of On Off extended
- On
- use_rsyslog
- (boolean) Change logging behaviour to log both access and error logs via rsyslog
- vhost_http_template
- (string) Apache vhost template (base64 encoded).
- vhost_https_template
- (string) Apache vhost template (base64 encoded).
- vhost_template_vars
- (string) Additional custom variables for the vhost templating, in python dict format