Skip to content
This repository has been archived by the owner on Apr 23, 2019. It is now read-only.

Implement custom blocks to be inserted in nginx config. #142

Closed
wants to merge 11 commits into from

Conversation

berkes
Copy link
Collaborator

@berkes berkes commented Nov 13, 2014

This is a go at #97

@@ -103,9 +103,11 @@
end
end

custom_configuration = app_info["nginx_custom"].reject{ |k,v| v.nil? || v.empty? }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused block argument - k. If it's necessary, use _ or _k as an argument name to indicate that it won't be used.
Line is too long. [86/80]
Space missing after comma.
Space missing to the left of {.

variables(
name: app,
domain_names: app_info["domain_names"],
enable_ssl: File.exists?("#{applications_root}/#{app}/shared/config/certificate.crt"),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line is too long. [94/80]

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing this involves a lot more then just wrapping the line.

Proper fix would be to either introduce some helper modules and call methods such as certificate_exists_for?(app).

The next best thing, and more chef-ish, is to make these blocks into LWRPs. That allows for a lot of cleaning up.

The next best thing is to extract all these into variables, but that really does not make the code more readable.

Alll this is is a much larger, and different task than what I'm trying to achieve in this PR,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's fine. I think I'm going to ignore the Hound line length setting and set it to 150 or something like that.

Also: agree with you on refactoring this into nice cheffy libraries and LWRPs. But let's first see what the best approach is right now.

@michiels
Copy link
Member

One suggestion from my part would be to make the custom_nginx subkeys a bit more verbose. So instead of before call it before_server so you know its outside of the server block.

Do you have a use case for these generic before and after blocks? Otherwise, I'd remove them for now and only focus on the things we'd want to put inside the server blocks.

@berkes
Copy link
Collaborator Author

berkes commented Nov 24, 2014

Do you have a use case for these generic before and after blocks? Otherwise, I'd remove them for now and only focus on the things we'd want to put inside the server blocks.

One thing I've used them for in the past is to allow custom server {} blocks. Those server-blocks can then contain:

  • Redirect domains, a list of domains that the application does not listen to, but who redirect to a canonical domain on which the domain does listen.
  • WWW- non www- redirection. In reality this is technical equivalent of above.
  • Provide alternative backends. E.g. during a migration we'd provide a v1 backend and a v2 backend; then on e.g. a whitelist of IP-addresses, set certain requests to the new "v2" backend.
  • Provide a (temporary) server-block that disallows access, provides a basic-auth request or serves a simple, temporary launching-soon html-page.

The fist two could best be actual features in the configuration json, something like redirect_domains: [] instead of providing a hack where people generate custom server blocks to deal with this. But for now, it is the simplest way to achieve such redirect-domains.

The alternative-backends is mostly a hack to work around a (temporary) case which, arguably, should be dealt with in the app itself. But when you can add arbitrary server blocks, you can solve it this way too.

@michiels
Copy link
Member

Thanks this makes sense. Especially for the redirect stuff. I would agree with also providing "redirect_domains" but I've also noted that are so much edge cases you might want to cover that sometimes just providing the nginx snippet yourself is much better.

Let's experiment with this approach. I'll test it and merge it in! Allright?

@berkes
Copy link
Collaborator Author

berkes commented Nov 24, 2014

You don't want to wait untill I've renamed them to before_server and after_server? Because I can do that, but probably not before thursday.

@michiels
Copy link
Member

@berkes If you like I can add a commit to your branch by pulling it from your remote. Would that be allright?

@berkes
Copy link
Collaborator Author

berkes commented Nov 24, 2014

yea, sure!

@michiels
Copy link
Member

Is there a way to merge this PRs on GitHub? I would like to retain this PR to do the changes :)

@jvanbaarsen
Copy link
Contributor

@michiels Not sure what you mean? You can push the "Merge Pull Request" button?

@michiels
Copy link
Member

I want to collaborate with @berkes on his branch by adding a commit myself. But the only way to do that is create a new branch in this repository and make a new PR of that, losing this discussion and PR in the process.

@michiels
Copy link
Member

What do you guys think of some documentation? I'm a bit afraid with cluttering the README with all kinds of "advanced" features. Maybe just use the Wiki pages to explain features like these?

@berkes
Copy link
Collaborator Author

berkes commented Dec 19, 2014

Documentation.

Below should go into
https://github.com/intercity/chef-repo/wiki/sample_host.json-explained#applications
when this PR is merged.

nginx_custom

The nginx_custom directive can be used to inject custom nginx
configuration at various point in the vhost configuration file.

  "active_applications": {
    "<appname>_<stage>": {
      ...
      "nginx_custom": {
        "before" => "",
        "server_main" => "",
        "server_app" => "",
        "server_ssl" => "",
        "server_ssl_app" => "",
        "upstream" => "",
        "after" => "",
       }

The template is the best reference where these will go. Below is a simplified
example for the unicorn-vhost (with upstream) and ssl enabled:

<%= @custom_configuration["before"] %>

server {
  listen 80;
  server_name example.com;
  root /u/app/example_com/current/public;

  try_files $uri/index.html $uri.html $uri @app;

  location @app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_pass http://example_com;
    <%= @custom_configuration["server_app"] %>
  }
  <%= @custom_configuration["server_main"] %>
}

server {
  listen 443 ssl;

  ssl_certificate /u/apps/example_com/shared/config/certificate.crt;
  ssl_certificate_key /u/apps/example_com/shared/config/certificate.key;

  server_name example.com;

  root /u/apps/example_com/current/public;

  location / {
    try_files $uri @app;
  }

  location @app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_redirect off;

    proxy_pass http://explained;
    <%= @custom_configuration["ssl_app"] %>
  }
  <%= @custom_configuration["ssl_main"] %>
}

upstream example_com {
  server unix:/u/apps/example_com/shared/tmp/sockets/unicorn.sock;
  <%= @custom_configuration["upstream"] %>
}

<%= @custom_configuration["after"] %>

Typical uses of the custom places:

  • before: extra server blocks to handle redirects, migrate domains or
    handle things like "www to non-www redirection"
  • server_app: config options such as options for passenger or the
    proxy.
  • server_main: include extra configs, such as redirects.
  • ssl_app and ssl_main: same as server_app and server_main, but for
    SSL. Note: if you set these, but don't have SSL-certificates
    configured, this block won't be rendered at all; the custom config will
    not be rendered at all.
  • upstream: directives such as server for load-balancing or fallback
    servers.
  • after: extra server blocks to handle fallthrough situations or
    define custom upstream blocks for fallback (e.g.
    offline-during-migration) situations.

Example

Given a file with redirects in
/u/apps/example_com/shared/config/nginx_rewrites.conf containing:

rewrite ^/tags/large-bags$ http://example.com/t/bags break;
rewrite ^/content/about$ http://example.com/t/about-us break;

You can now include that file in the vhost with (note the trailing ;):

  "active_applications": {
    "<appname>_<stage>": {
      ...
      "nginx_custom": {
        "server_main": "include /u/apps/example_com/shared/config/nginx_rewrites.conf;"
       }

Resulting in a vhost:

server {
  listen 80;
  server_name example.com;
  root /u/app/example_com/current/public;

  try_files $uri/index.html $uri.html $uri @app;

  location @app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_pass http://example_com;
  }
  include /u/apps/example_com/shared/config/nginx_rewrites.conf;
}

You now have a file where you can maintain custom redirects for
backwards compatibility of an API or for SEO-purposes.

Troubleshooting

The contents of the custom_conf will be placed in there literally. So,
if you add bogus code, forget a trailing ; or do something else that
is invalid, the vhost won't be valid anymore and the reload will fail.
On the server, you can investigate /var/logs/nginx/error.log which
contains the error.
Nginx will be reloaded (not stopped+started or restarted) which means
the old configuration, the one before the error was introduced and a
reload attempted, will remain active: the server should remain up.
For anything but the most simple directives it is advised to test these
on a test-server; e.g. the Vagrant that ships with chef-repo.

@@ -1,7 +1,7 @@
name "backups"
maintainer "Firmhouse"
maintainer_email "[email protected]"
license "Apache 2.0"
license "MIT"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put one space between the method name and the first argument.

@berkes
Copy link
Collaborator Author

berkes commented Dec 24, 2014

Fixing the mergecomflicts within this PR will introduce a lot of needless commits. I'll rebase this on master and on @michiels branch and then recreate a new PR.

@berkes berkes closed this Dec 24, 2014
@jvanbaarsen
Copy link
Contributor

@berkes Ok thanks!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants