ConfigLMM 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -0
  3. data/Examples/Implemented.mm.yaml +75 -1
  4. data/Plugins/Apps/Authentik/Authentik-ProxyOutpost.container +14 -0
  5. data/Plugins/Apps/Authentik/Authentik-Server.container +19 -0
  6. data/Plugins/Apps/Authentik/Authentik-Worker.container +18 -0
  7. data/Plugins/Apps/Authentik/Authentik.conf.erb +42 -0
  8. data/Plugins/Apps/Authentik/Authentik.lmm.rb +95 -0
  9. data/Plugins/Apps/BookStack/BookStack.conf.erb +41 -0
  10. data/Plugins/Apps/BookStack/BookStack.container +15 -0
  11. data/Plugins/Apps/BookStack/BookStack.lmm.rb +80 -0
  12. data/Plugins/Apps/Cassandra/Cassandra.lmm.rb +41 -0
  13. data/Plugins/Apps/Discourse/Discourse-Sidekiq.container +17 -0
  14. data/Plugins/Apps/Discourse/Discourse.conf.erb +41 -0
  15. data/Plugins/Apps/Discourse/Discourse.container +17 -0
  16. data/Plugins/Apps/Discourse/Discourse.lmm.rb +95 -0
  17. data/Plugins/Apps/Dovecot/Dovecot.lmm.rb +171 -0
  18. data/Plugins/Apps/ERPNext/ERPNext-Frontend.container +19 -0
  19. data/Plugins/Apps/ERPNext/ERPNext-Queue.container +17 -0
  20. data/Plugins/Apps/ERPNext/ERPNext-Scheduler.container +17 -0
  21. data/Plugins/Apps/ERPNext/ERPNext-Websocket.container +19 -0
  22. data/Plugins/Apps/ERPNext/ERPNext.container +18 -0
  23. data/Plugins/Apps/ERPNext/ERPNext.lmm.rb +193 -0
  24. data/Plugins/Apps/ERPNext/ERPNext.network +12 -0
  25. data/Plugins/Apps/ERPNext/sites/apps.json +10 -0
  26. data/Plugins/Apps/ERPNext/sites/apps.txt +3 -0
  27. data/Plugins/Apps/ERPNext/sites/common_site_config.json +11 -0
  28. data/Plugins/Apps/GitLab/GitLab.container +18 -0
  29. data/Plugins/Apps/GitLab/GitLab.lmm.rb +100 -0
  30. data/Plugins/Apps/LetsEncrypt/LetsEncrypt.lmm.rb +57 -0
  31. data/Plugins/Apps/LetsEncrypt/hooks/dovecot.sh +2 -0
  32. data/Plugins/Apps/LetsEncrypt/hooks/nginx.sh +2 -0
  33. data/Plugins/Apps/LetsEncrypt/hooks/postfix.sh +2 -0
  34. data/Plugins/Apps/LetsEncrypt/renew-certificates.service +7 -0
  35. data/Plugins/Apps/LetsEncrypt/renew-certificates.timer +12 -0
  36. data/Plugins/Apps/LetsEncrypt/rfc2136.ini +11 -0
  37. data/Plugins/Apps/MariaDB/MariaDB.lmm.rb +115 -0
  38. data/Plugins/Apps/Matrix/Element.container +14 -0
  39. data/Plugins/Apps/Matrix/Matrix.conf.erb +49 -5
  40. data/Plugins/Apps/Matrix/Matrix.lmm.rb +86 -1
  41. data/Plugins/Apps/Matrix/Synapse.container +17 -0
  42. data/Plugins/Apps/Matrix/config.json +50 -0
  43. data/Plugins/Apps/Matrix/homeserver.yaml +70 -0
  44. data/Plugins/Apps/Matrix/log.config +30 -0
  45. data/Plugins/Apps/Nextcloud/Nextcloud.conf.erb +48 -10
  46. data/Plugins/Apps/Nextcloud/Nextcloud.lmm.rb +83 -1
  47. data/Plugins/Apps/Nextcloud/config.php +18 -0
  48. data/Plugins/Apps/Nginx/conf.d/configlmm.conf +71 -0
  49. data/Plugins/Apps/Nginx/config-lmm/errors.conf +11 -5
  50. data/Plugins/Apps/Nginx/config-lmm/proxy.conf +5 -1
  51. data/Plugins/Apps/Nginx/main.conf.erb +31 -0
  52. data/Plugins/Apps/Nginx/nginx.conf +3 -68
  53. data/Plugins/Apps/Nginx/nginx.lmm.rb +83 -22
  54. data/Plugins/Apps/Nginx/proxy.conf.erb +13 -3
  55. data/Plugins/Apps/Odoo/Odoo.conf.erb +30 -13
  56. data/Plugins/Apps/Odoo/Odoo.container +18 -0
  57. data/Plugins/Apps/Odoo/Odoo.lmm.rb +62 -2
  58. data/Plugins/Apps/Odoo/odoo.conf +37 -0
  59. data/Plugins/Apps/OpenVidu/Ingress.container +18 -0
  60. data/Plugins/Apps/OpenVidu/OpenVidu.conf.erb +34 -0
  61. data/Plugins/Apps/OpenVidu/OpenVidu.container +16 -0
  62. data/Plugins/Apps/OpenVidu/OpenVidu.lmm.rb +90 -0
  63. data/Plugins/Apps/OpenVidu/OpenViduCall.conf.erb +35 -0
  64. data/Plugins/Apps/OpenVidu/OpenViduCall.container +15 -0
  65. data/Plugins/Apps/OpenVidu/ingress.yaml +10 -0
  66. data/Plugins/Apps/OpenVidu/livekit.yaml +13 -0
  67. data/Plugins/Apps/PHP-FPM/PHP-FPM.lmm.rb +95 -0
  68. data/Plugins/Apps/Peppermint/Peppermint.conf.erb +60 -0
  69. data/Plugins/Apps/Peppermint/Peppermint.container +15 -0
  70. data/Plugins/Apps/Peppermint/Peppermint.lmm.rb +58 -0
  71. data/Plugins/Apps/Postfix/Postfix.lmm.rb +165 -31
  72. data/Plugins/Apps/Postfix/smtpd.conf +3 -0
  73. data/Plugins/Apps/PostgreSQL/PostgreSQL.lmm.rb +242 -24
  74. data/Plugins/Apps/Roundcube/Roundcube.conf.erb +75 -0
  75. data/Plugins/Apps/Roundcube/Roundcube.lmm.rb +145 -0
  76. data/Plugins/Apps/SSH/SSH.lmm.rb +51 -0
  77. data/Plugins/Apps/Tunnel/tunnel.lmm.rb +63 -0
  78. data/Plugins/Apps/Tunnel/tunnelTCP.service +9 -0
  79. data/Plugins/Apps/Tunnel/tunnelTCP.socket +9 -0
  80. data/Plugins/Apps/Tunnel/tunnelUDP.service +9 -0
  81. data/Plugins/Apps/Tunnel/tunnelUDP.socket +9 -0
  82. data/Plugins/Apps/UVdesk/UVdesk.conf.erb +52 -0
  83. data/Plugins/Apps/UVdesk/UVdesk.lmm.rb +85 -0
  84. data/Plugins/Apps/Valkey/Valkey.lmm.rb +34 -1
  85. data/Plugins/Apps/Vaultwarden/Vaultwarden.conf.erb +35 -18
  86. data/Plugins/Apps/Vaultwarden/Vaultwarden.container +16 -0
  87. data/Plugins/Apps/Vaultwarden/Vaultwarden.lmm.rb +46 -3
  88. data/Plugins/Apps/Wiki.js/Wiki.js.conf.erb +42 -0
  89. data/Plugins/Apps/Wiki.js/Wiki.js.container +15 -0
  90. data/Plugins/Apps/Wiki.js/Wiki.js.lmm.rb +61 -0
  91. data/Plugins/Apps/gollum/gollum.conf.erb +84 -19
  92. data/Plugins/Apps/gollum/gollum.container +15 -0
  93. data/Plugins/Apps/gollum/gollum.lmm.rb +48 -11
  94. data/Plugins/OS/Linux/Debian/preseed.cfg.erb +62 -0
  95. data/Plugins/OS/Linux/Distributions.yaml +42 -0
  96. data/Plugins/OS/Linux/Flavours.yaml +11 -0
  97. data/Plugins/OS/Linux/Linux.lmm.rb +362 -41
  98. data/Plugins/OS/Linux/Packages.yaml +88 -5
  99. data/Plugins/OS/Linux/Proxmox/answer.toml.erb +30 -0
  100. data/Plugins/OS/Linux/WireGuard/WireGuard.lmm.rb +137 -0
  101. data/Plugins/OS/Linux/WireGuard/wg0.conf.erb +15 -0
  102. data/Plugins/OS/Linux/systemd/systemd.lmm.rb +28 -0
  103. data/Plugins/OS/Linux/systemd/user-0.slice +9 -0
  104. data/Plugins/OS/Linux/systemd/user@.service.d/delegate.conf +3 -0
  105. data/Plugins/Platforms/GoDaddy/GoDaddy.lmm.rb +7 -3
  106. data/Plugins/Platforms/libvirt/libvirt.lmm.rb +3 -2
  107. data/Plugins/Services/DNS/PowerDNS.lmm.rb +158 -8
  108. data/README.md +6 -0
  109. data/bootstrap.sh +92 -0
  110. data/lib/ConfigLMM/Framework/plugins/dns.rb +1 -2
  111. data/lib/ConfigLMM/Framework/plugins/linuxApp.rb +249 -45
  112. data/lib/ConfigLMM/Framework/plugins/nginxApp.rb +56 -7
  113. data/lib/ConfigLMM/Framework/plugins/plugin.rb +112 -16
  114. data/lib/ConfigLMM/cli.rb +3 -1
  115. data/lib/ConfigLMM/commands/cleanup.rb +1 -0
  116. data/lib/ConfigLMM/commands/configsCommand.rb +3 -1
  117. data/lib/ConfigLMM/io/configList.rb +3 -1
  118. data/lib/ConfigLMM/state.rb +10 -2
  119. data/lib/ConfigLMM/version.rb +1 -1
  120. metadata +82 -3
  121. data/Plugins/Apps/Nginx/main.conf +0 -30
@@ -0,0 +1,30 @@
1
+ version: 1
2
+
3
+ formatters:
4
+ precise:
5
+
6
+ format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
7
+
8
+ handlers:
9
+
10
+ console:
11
+ class: logging.StreamHandler
12
+ formatter: precise
13
+
14
+ loggers:
15
+ # This is just here so we can leave `loggers` in the config regardless of whether
16
+ # we configure other loggers below (avoid empty yaml dict error).
17
+ _placeholder:
18
+ level: "INFO"
19
+
20
+ synapse.storage.SQL:
21
+ # beware: increasing this to DEBUG will make synapse log sensitive
22
+ # information such as access tokens.
23
+ level: INFO
24
+
25
+ root:
26
+ level: INFO
27
+ handlers: [console]
28
+
29
+
30
+ disable_existing_loggers: false
@@ -1,9 +1,11 @@
1
1
 
2
-
3
-
4
2
  upstream nextcloud
5
3
  {
4
+ <% if config['Server'] %>
5
+ server <%= config['Server'] %>;
6
+ <% else %>
6
7
  server unix:/run/php-fpm/nextcloud.sock;
8
+ <% end %>
7
9
  }
8
10
 
9
11
  server
@@ -12,13 +14,22 @@ server
12
14
  listen <%= config['Port'] %>;
13
15
  listen [::]:<%= config['Port'] %>;
14
16
  <% else %>
15
- listen <%= config['Port'] %> ssl;
16
- listen [::]:<%= config['Port'] %> ssl;
17
- http2 on;
17
+ <% if config['NginxVersion'] >= 1.25 %>
18
+ listen <%= config['Port'] %> ssl;
19
+ listen [::]:<%= config['Port'] %> ssl;
20
+ http2 on;
21
+ http3 on;
22
+ quic_retry on;
23
+ add_header Alt-Svc 'h3=":<%= config['Port'] %>"; ma=86400';
24
+ <% else %>
25
+ listen <%= config['Port'] %> ssl http2;
26
+ listen [::]:<%= config['Port'] %> ssl http2;
27
+ <% end %>
28
+
18
29
  include config-lmm/ssl.conf;
19
30
  <% end %>
20
31
 
21
- <%= config['Domain'] %>;
32
+ server_name <%= config['Domain'] %>;
22
33
 
23
34
  access_log /var/log/nginx/nextcloud.access.log;
24
35
  error_log /var/log/nginx/nextcloud.error.log;
@@ -133,17 +144,23 @@ server
133
144
  fastcgi_max_temp_file_size 0;
134
145
  }
135
146
 
147
+ # Rule borrowed from `.htaccess`
148
+ location /remote {
149
+ return 301 /remote.php$request_uri;
150
+ }
151
+
136
152
  # Serve static files
137
153
  location ~ \.(?:css|js|mjs|svg|gif|png|jpg|ico|wasm|tflite|map|ogg|flac)$ {
138
154
  try_files $uri /index.php$request_uri;
139
155
  # HTTP response headers borrowed from Nextcloud `.htaccess`
140
- add_header Cache-Control "public, max-age=15778463$assetImmutable";
141
156
  add_header Referrer-Policy "no-referrer" always;
142
157
  add_header X-Content-Type-Options "nosniff" always;
143
158
  add_header X-Frame-Options "SAMEORIGIN" always;
144
159
  add_header X-Permitted-Cross-Domain-Policies "none" always;
145
160
  add_header X-Robots-Tag "noindex, nofollow" always;
146
161
  add_header X-XSS-Protection "1; mode=block" always;
162
+ add_header Cache-Control "public, max-age=15778463$assetImmutable";
163
+ add_header X-XSS-Protection "1; mode=block" always;
147
164
  access_log off; # Optional: Don't log access to assets
148
165
  }
149
166
 
@@ -153,9 +170,30 @@ server
153
170
  access_log off; # Optional: Don't log access to assets
154
171
  }
155
172
 
156
- # Rule borrowed from `.htaccess`
157
- location /remote {
158
- return 301 /remote.php$request_uri;
173
+ location /wapps/ {
174
+ alias /var/lib/nextcloud/apps/;
175
+
176
+ # Serve static files
177
+ location ~ \.(?:css|js|mjs|svg|gif|png|jpg|ico|wasm|tflite|map|ogg|flac)$ {
178
+ try_files $uri /index.php$request_uri;
179
+ # HTTP response headers borrowed from Nextcloud `.htaccess`
180
+ add_header Referrer-Policy "no-referrer" always;
181
+ add_header X-Content-Type-Options "nosniff" always;
182
+ add_header X-Frame-Options "SAMEORIGIN" always;
183
+ add_header X-Permitted-Cross-Domain-Policies "none" always;
184
+ add_header X-Robots-Tag "noindex, nofollow" always;
185
+ add_header X-XSS-Protection "1; mode=block" always;
186
+ add_header Cache-Control "public, max-age=15778463$assetImmutable";
187
+ add_header X-XSS-Protection "1; mode=block" always;
188
+ access_log off; # Optional: Don't log access to assets
189
+ }
190
+
191
+ location ~ \.woff2?$ {
192
+ try_files $uri /index.php$request_uri;
193
+ expires 7d; # Cache-Control policy borrowed from `.htaccess`
194
+ access_log off; # Optional: Don't log access to assets
195
+ }
196
+
159
197
  }
160
198
 
161
199
  location / {
@@ -3,6 +3,10 @@ module ConfigLMM
3
3
  module LMM
4
4
  class Nextcloud < Framework::NginxApp
5
5
 
6
+ USER = 'nextcloud'
7
+ HOME_DIR = '/var/lib/nextcloud'
8
+ PACKAGE_NAME = 'Nextcloud'
9
+
6
10
  def actionNextcloudBuild(id, target, state, context, options)
7
11
  writeNginxConfig(__dir__, 'Nextcloud', id, target, state, context, options)
8
12
  end
@@ -12,10 +16,88 @@ module ConfigLMM
12
16
  end
13
17
 
14
18
  def actionNextcloudDeploy(id, target, activeState, context, options)
15
- if !target['Location'] || target['Location'] == '@me'
19
+ if target['Location'] && target['Location'] != '@me'
20
+ uri = Addressable::URI.parse(target['Location'])
21
+ raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
22
+ self.class.sshStart(uri) do |ssh|
23
+ Framework::LinuxApp.ensurePackages([PHP_FPM::PHPFPM_PACKAGE], ssh)
24
+ Framework::LinuxApp.ensureServiceAutoStartOverSSH(PHP_FPM::PHPFPM_SERVICE, ssh)
25
+ distroInfo = Framework::LinuxApp.ensurePackages([PACKAGE_NAME], ssh)
26
+ addUserCmd = "#{distroInfo['CreateServiceUser']} --home-dir '#{HOME_DIR}' --create-home --comment 'Nextcloud' #{USER}"
27
+ self.class.sshExec!(ssh, addUserCmd, true)
28
+ self.class.sshExec!(ssh, "mkdir -p /var/log/php/ /var/lib/nextcloud/apps/ /var/lib/nextcloud/data/")
29
+ self.class.sshExec!(ssh, "touch /var/log/php/nextcloud.errors.log")
30
+ self.class.sshExec!(ssh, "touch /var/log/php/nextcloud.mail.log")
31
+ self.class.sshExec!(ssh, "chown #{USER}:#{USER} /var/log/php/nextcloud.errors.log")
32
+ self.class.sshExec!(ssh, "chown #{USER}:#{USER} /var/log/php/nextcloud.mail.log")
33
+ PHP_FPM::fixConfigFileOverSSH(distroInfo, ssh)
34
+
35
+ webappsDir = PHP_FPM::webappsDir(distroInfo)
36
+ configDir = webappsDir + 'nextcloud/config/'
37
+ if !self.class.remoteFilePresent?(configDir + 'config.php', ssh)
38
+ self.class.uploadNotPresent(__dir__ + '/config.php', configDir, ssh)
39
+ self.class.sshExec!(ssh, "sed -i \"s|'instanceid' .*|'instanceid' => '#{SecureRandom.alphanumeric(10)}',|\" #{configDir}config.php")
40
+ self.class.sshExec!(ssh, "touch #{configDir}CAN_INSTALL")
41
+ self.class.sshExec!(ssh, "sed -i 's|/usr/share/webapps/|#{webappsDir}|' #{configDir}config.php")
42
+ end
43
+ self.class.sshExec!(ssh, "chown -R nextcloud:nextcloud #{configDir}")
44
+ self.class.sshExec!(ssh, "chown -R nextcloud:nextcloud /var/lib/nextcloud/")
45
+
46
+ target['Database'] ||= {}
47
+ if !target['Database']['Type'] || target['Database']['Type'] == 'pgsql'
48
+ PostgreSQL.createRemoteUserAndDBOverSSH(target['Database'], USER, nil, ssh)
49
+ end
50
+
51
+ target['User'] = USER unless target['User']
52
+ name = 'nextcloud'
53
+ self.updateRemoteFile(ssh, PHP_FPM.configDir(distroInfo) + name + '.conf', options, false, ';') do |configLines|
54
+ PHP_FPM.writeConfig(name, target, distroInfo, configLines)
55
+ end
56
+
57
+ Framework::LinuxApp.startServiceOverSSH(PHP_FPM::PHPFPM_SERVICE, ssh)
58
+
59
+ self.class.ensurePackage(ssh)
60
+ self.class.prepareNginxConfig(target, ssh)
61
+ self.writeNginxConfig(__dir__, 'Nextcloud', id, target, state, context, options)
62
+ distroInfo = Framework::LinuxApp.currentDistroInfo(ssh)
63
+ webappsDir = PHP_FPM::webappsDir(distroInfo)
64
+ nginxFile = options['output'] + '/nginx/servers-lmm/Nextcloud.conf'
65
+ `sed -i 's|root .*|root #{webappsDir}nextcloud;|' #{nginxFile}`
66
+ deployNginxConfig(id, target, activeState, context, options)
67
+ Framework::LinuxApp.startService(NGINX_PACKAGE, ssh)
68
+ self.class.reload(ssh)
69
+ end
70
+ else
16
71
  deployNginxConfig(id, target, activeState, context, options)
17
72
  activeState['Location'] = '@me'
18
73
  end
74
+ activeState['Status'] = State::STATUS_DEPLOYED
75
+ end
76
+
77
+ def cleanup(configs, state, context, options)
78
+ cleanupType(:Nextcloud, configs, state, context, options) do |item, id, state, context, options, ssh|
79
+ self.cleanupNginxConfig('Nextcloud', id, state, context, options, ssh)
80
+ self.class.reload(ssh, options[:dry])
81
+ distroInfo = Framework::LinuxApp.currentDistroInfo(ssh)
82
+ rm(PHP_FPM.configDir(distroInfo) + 'nextcloud.conf', options[:dry], ssh)
83
+ Framework::LinuxApp.reloadService(PHP_FPM::PHPFPM_SERVICE, ssh, options[:dry])
84
+ Framework::LinuxApp.removePackage(PACKAGE_NAME, ssh, options[:dry])
85
+ state.item(id)['Status'] = State::STATUS_DELETED unless options[:dry]
86
+ if options[:destroy]
87
+ rm(PHP_FPM::webappsDir(distroInfo) + 'nextcloud', options[:dry], ssh)
88
+ item['Database'] ||= {}
89
+ if !item['Database']['Type'] || item['Database']['Type'] == 'pgsql'
90
+ PostgreSQL.dropUserAndDB(item['Database'], USER, ssh, options[:dry])
91
+ end
92
+ Framework::LinuxApp.deleteUserAndGroup(USER, ssh, options[:dry])
93
+ rm('/var/log/php/nextcloud.access.log', options[:dry], ssh)
94
+ rm('/var/log/php/nextcloud.errors.log', options[:dry], ssh)
95
+ rm('/var/log/php/nextcloud.mail.log', options[:dry], ssh)
96
+ rm('/var/log/nginx/nextcloud.access.log', options[:dry], ssh)
97
+ rm('/var/log/nginx/nextcloud.error.log', options[:dry], ssh)
98
+ state.item(id)['Status'] = State::STATUS_DESTROYED unless options[:dry]
99
+ end
100
+ end
19
101
  end
20
102
 
21
103
  end
@@ -0,0 +1,18 @@
1
+ <?php
2
+
3
+ $CONFIG = [
4
+ 'instanceid' => '',
5
+ 'datadirectory' => '/var/lib/nextcloud/data/',
6
+ 'apps_paths' => [
7
+ [
8
+ 'path'=> '/usr/share/webapps/nextcloud/apps',
9
+ 'url' => '/apps',
10
+ 'writable' => false,
11
+ ],
12
+ [
13
+ 'path'=> '/var/lib/nextcloud/apps',
14
+ 'url' => '/wapps',
15
+ 'writable' => true,
16
+ ],
17
+ ]
18
+ ];
@@ -0,0 +1,71 @@
1
+
2
+ server_tokens off;
3
+
4
+ tcp_nopush on;
5
+
6
+ # Needed for OCSP stapling
7
+ resolver 127.0.0.53;
8
+
9
+
10
+ # types_hash_max_size 4096;
11
+ # types_hash_bucket_size 64;
12
+ # proxy_headers_hash_max_size 512;
13
+ # proxy_headers_hash_bucket_size 128;
14
+
15
+
16
+ gzip on;
17
+ gzip_vary on;
18
+ gzip_proxied any;
19
+ gzip_comp_level 6;
20
+ gzip_min_length 256;
21
+
22
+ # do not remove ETag headers
23
+ gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
24
+
25
+ gzip_types application/atom+xml text/javascript text/xml application/xml+rss application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
26
+
27
+
28
+ charset utf-8;
29
+ charset_types text/css text/plain text/xml text/javascript text/vnd.wap.wml application/json application/javascript application/xml application/xml+rss application/rss+xm image/svg+xml;
30
+ proxy_intercept_errors on;
31
+ fastcgi_intercept_errors on;
32
+
33
+ map '' $WithHost {
34
+ default '';
35
+ }
36
+
37
+ map "$WithHost" $ProxyHost {
38
+ default $host;
39
+ ~. $WithHost;
40
+ }
41
+
42
+ map $http_accept $errorExtension
43
+ {
44
+ default html;
45
+ ~application/json json;
46
+ ~application/activity+json json;
47
+ }
48
+
49
+ map $http_upgrade $connectionUpgrade
50
+ {
51
+ default upgrade;
52
+ '' '';
53
+ }
54
+
55
+ # Set the `immutable` cache control options only for assets with a cache busting `v` argument
56
+ map $arg_v $assetImmutable
57
+ {
58
+ "" "";
59
+ default ", immutable";
60
+ }
61
+
62
+ root /srv/www/root;
63
+
64
+ ssl_certificate "/etc/letsencrypt/live/Wildcard/fullchain.pem";
65
+ ssl_certificate_key "/etc/letsencrypt/live/Wildcard/privkey.pem";
66
+ ssl_trusted_certificate "/etc/letsencrypt/live/Wildcard/chain.pem";
67
+
68
+ # Load modular configuration files from the /etc/nginx/servers directory.
69
+ # See http://nginx.org/en/docs/ngx_core_module.html#include
70
+ # for more information.
71
+ include servers-lmm/*.conf;
@@ -1,7 +1,13 @@
1
1
 
2
2
  # add one directive for each http status code
3
3
  error_page 301 /_errors_/HTTP301.$errorExtension;
4
- error_page 302 /_errors_/HTTP302.$errorExtension;
4
+
5
+ # Looks like enabling custom 302 can be problematic
6
+ # due to apps using multiple Set-Cookie headers
7
+ # for example this breaks BookStack
8
+ # so lets not use it by default
9
+ #error_page 302 /_errors_/HTTP302.$errorExtension;
10
+
5
11
  error_page 303 /_errors_/HTTP303.$errorExtension;
6
12
  error_page 307 /_errors_/HTTP307.$errorExtension;
7
13
  error_page 308 /_errors_/HTTP308.$errorExtension;
@@ -23,9 +29,9 @@ error_page 533 /_errors_/HTTP533.$errorExtension;
23
29
  location /_errors_/ {
24
30
  include config-lmm/public.conf;
25
31
 
26
- alias /srv/http/errors/;
32
+ add_header Location $upstream_http_location;
33
+ add_header Set-Cookie $upstream_http_set_cookie;
34
+
35
+ alias /srv/www/errors/;
27
36
  internal;
28
37
  }
29
-
30
- add_header Location $upstream_http_location;
31
- add_header Set-Cookie $upstream_http_set_cookie;
@@ -1,7 +1,7 @@
1
1
 
2
2
  proxy_http_version 1.1;
3
3
 
4
- proxy_set_header Host $host;
4
+ proxy_set_header Host $ProxyHost;
5
5
  proxy_set_header X-Real-IP $remote_addr;
6
6
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
7
7
  proxy_set_header X-Forwarded-Proto $scheme;
@@ -13,3 +13,7 @@ proxy_set_header Connection $connectionUpgrade;
13
13
 
14
14
  # proxy_set_header Proxy "";
15
15
  proxy_pass_header Server;
16
+
17
+ proxy_ssl_protocols TLSv1.2 TLSv1.3;
18
+
19
+ proxy_connect_timeout 2s;
@@ -0,0 +1,31 @@
1
+
2
+ server {
3
+ listen 80 default_server;
4
+ listen [::]:80 default_server;
5
+ server_name _;
6
+
7
+ include config-lmm/errors.conf;
8
+
9
+ deny all;
10
+ }
11
+
12
+ server {
13
+ <% if config['NginxVersion'] >= 1.25 %>
14
+ listen 443 default_server ssl reuseport;
15
+ listen [::]:443 default_server ssl reuseport;
16
+ http2 on;
17
+ <% else %>
18
+ listen 443 default_server ssl reuseport http2;
19
+ listen [::]:443 default_server ssl reuseport http2;
20
+ <% end %>
21
+
22
+ server_name _;
23
+
24
+ deny all;
25
+
26
+ ssl_early_data on;
27
+
28
+ include config-lmm/errors.conf;
29
+ include config-lmm/security.conf;
30
+ include config-lmm/ssl.conf;
31
+ }
@@ -1,90 +1,25 @@
1
1
 
2
- load_module "/usr/lib/nginx/modules/ngx_http_passenger_module.so";
3
- #load_module "/usr/lib/nginx/modules/ngx_http_stub_status_module.so";
4
-
5
- #user http;
6
2
  worker_processes 4;
7
3
 
8
- #error_log logs/error.log;
9
- #error_log logs/error.log notice;
10
- #error_log logs/error.log info;
11
4
  error_log /var/log/nginx/error.log info;
12
5
 
13
- #pid logs/nginx.pid;
14
-
15
-
16
6
  events {
17
7
  worker_connections 1024;
8
+ use epoll;
18
9
  }
19
10
 
20
-
21
11
  http {
22
12
  include mime.types;
23
13
  default_type application/octet-stream;
24
- server_tokens off;
25
-
26
- types_hash_max_size 4096;
27
- types_hash_bucket_size 64;
28
- proxy_headers_hash_max_size 512;
29
- proxy_headers_hash_bucket_size 128;
30
-
31
- #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
32
- # '$status $body_bytes_sent "$http_referer" '
33
- # '"$http_user_agent" "$http_x_forwarded_for"';
34
-
35
- #access_log logs/access.log main;
36
14
 
37
15
  sendfile on;
38
- tcp_nopush on;
39
- resolver 127.0.0.53;
40
-
41
- gzip on;
42
- gzip_vary on;
43
- gzip_proxied any;
44
- gzip_comp_level 6;
45
- gzip_min_length 256;
46
-
47
- # do not remove ETag headers
48
- gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
49
-
50
- gzip_types application/atom+xml text/javascript text/xml application/xml+rss application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
51
-
52
-
53
- charset utf-8;
54
- charset_types text/css text/plain text/xml text/javascript text/vnd.wap.wml application/json application/javascript application/xml application/xml+rss application/rss+xm image/svg+xml;
55
- proxy_intercept_errors on;
56
- fastcgi_intercept_errors on;
57
-
58
- map $http_accept $errorExtension
59
- {
60
- default html;
61
- ~application/json json;
62
- ~application/activity+json json;
63
- }
64
-
65
- map $http_upgrade $connectionUpgrade
66
- {
67
- default upgrade;
68
- '' '';
69
- }
70
-
71
- # Set the `immutable` cache control options only for assets with a cache busting `v` argument
72
- map $arg_v $assetImmutable
73
- {
74
- "" "";
75
- default ", immutable";
76
- }
77
-
78
- passenger_ruby /usr/bin/ruby;
79
- passenger_root /usr/lib/passenger;
80
16
 
81
- root /srv/http/root;
17
+ include conf.d/*.conf;
82
18
 
83
19
  include /etc/nginx/main.conf;
84
20
 
85
21
  # Load modular configuration files from the /etc/nginx/servers directory.
86
22
  # See http://nginx.org/en/docs/ngx_core_module.html#include
87
23
  # for more information.
88
- include /etc/nginx/servers/*.conf;
89
- include /etc/nginx/servers-lmm/*.conf;
24
+ include vhosts.d/*.conf;
90
25
  }
@@ -2,19 +2,20 @@
2
2
  module ConfigLMM
3
3
  module LMM
4
4
  class Nginx < Framework::NginxApp
5
-
6
- CONFIG_DIR = '/etc/nginx/'
7
- HTTP_DIR = '/srv/http/'
5
+ CERTBOT_PACKAGE = 'CertBotNginx'
6
+ ERROR_PAGES_REPO = 'https://github.com/HttpErrorPages/HttpErrorPages.git'
8
7
 
9
8
  def actionNginxBuild(id, target, activeState, context, options)
9
+
10
10
  dir = options['output'] + '/nginx/'
11
- mkdir(dir, options[:dry])
11
+ mkdir(dir + 'conf.d', options[:dry])
12
+ mkdir(dir + 'servers-lmm', options[:dry])
12
13
  copy(__dir__ + '/config-lmm', dir, options[:dry])
13
- # TODO, maybe evaluate them as template?
14
14
  copy(__dir__ + '/nginx.conf', dir, options[:dry])
15
- copy(__dir__ + '/main.conf', dir, options[:dry])
16
- mkdir(options['output'] + HTTP_DIR + 'root', options[:dry])
17
- mkdir(options['output'] + HTTP_DIR + 'errors', options[:dry])
15
+ copy(__dir__ + '/conf.d/configlmm.conf', dir + 'conf.d/', options[:dry])
16
+
17
+ mkdir(options['output'] + WWW_DIR + 'root', options[:dry])
18
+ mkdir(options['output'] + WWW_DIR + 'errors', options[:dry])
18
19
  end
19
20
 
20
21
  # TODO
@@ -25,13 +26,68 @@ module ConfigLMM
25
26
  def actionNginxDeploy(id, target, activeState, context, options)
26
27
  dir = options['output'] + '/nginx/'
27
28
 
28
- if !target['Location'] || target['Location'] == '@me'
29
+ if target['Location'] && target['Location'] != '@me'
30
+ uri = Addressable::URI.parse(target['Location'])
31
+ raise Framework::PluginProcessError.new("Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
32
+ self.class.sshStart(uri) do |ssh|
33
+ Framework::LinuxApp.ensurePackages([CERTBOT_PACKAGE], ssh)
34
+ self.class.prepareNginxConfig(target, ssh)
35
+
36
+ self.class.sshExec!(ssh, "mkdir -p #{CONFIG_DIR}conf.d")
37
+ self.class.sshExec!(ssh, "mkdir -p #{WWW_DIR}root")
38
+ self.class.sshExec!(ssh, "mkdir -p #{WWW_DIR}errors")
39
+ ssh.scp.upload!(dir + 'nginx.conf', CONFIG_DIR + 'nginx.conf')
40
+ ssh.scp.upload!(dir + 'conf.d/configlmm.conf', CONFIG_DIR + 'conf.d/configlmm.conf')
41
+ resolverIP = self.class.sshExec!(ssh, "cat /etc/resolv.conf | grep 'nameserver' | grep -v ':' | head -n 1 | cut -d ' ' -f 2").strip
42
+ self.class.sshExec!(ssh, "sed -i 's|^resolver .*|resolver #{resolverIP};|' /etc/nginx/conf.d/configlmm.conf")
43
+
44
+ self.class.uploadFolder(dir + 'config-lmm', CONFIG_DIR, ssh)
45
+ self.class.uploadFolder(dir + 'servers-lmm', CONFIG_DIR, ssh)
46
+
47
+ template = ERB.new(File.read(__dir__ + '/main.conf.erb'))
48
+ renderTemplate(template, target, dir + 'main.conf', options)
49
+ ssh.scp.upload!(dir + 'main.conf', CONFIG_DIR + 'main.conf')
50
+
51
+ if !self.class.remoteFilePresent?(WWW_DIR + 'errors/HTTP500.html', ssh)
52
+ errorPages = File.expand_path(REPOS_CACHE + '/HttpErrorPages')
53
+ if !File.exist?(errorPages)
54
+ mkdir(File.expand_path(REPOS_CACHE), false)
55
+ begin
56
+ Framework::LinuxApp.ensurePackages(['git', 'Yarn'], '@me')
57
+ rescue RuntimeError => error
58
+ prompt.say(error, :color => :red)
59
+ end
60
+ `cd #{REPOS_CACHE} && git clone --quiet #{ERROR_PAGES_REPO} > /dev/null`
61
+ end
62
+ `cd #{errorPages} && yarn install --silent`
63
+ `cd #{errorPages} && yarn run static config-dist.json > /dev/null`
64
+ `cd #{errorPages} && cp -R dist errors`
65
+ self.class.uploadFolder(errorPages + '/errors', WWW_DIR, ssh)
66
+ end
67
+
68
+ Framework::LinuxApp.createCertificateOverSSH(ssh)
69
+ end
70
+ else
71
+ self.class.prepareNginxConfig(target, nil)
72
+
29
73
  copy(dir + '/config-lmm', CONFIG_DIR, options[:dry])
30
- copyNotPresent(dir + '/nginx.conf', CONFIG_DIR, options[:dry])
31
- copyNotPresent(dir + '/main.conf', CONFIG_DIR, options[:dry])
32
- copyNotPresent(dir + '/servers-lmm', CONFIG_DIR, options['dry'])
33
- mkdir(HTTP_DIR + 'root', options[:dry])
34
- mkdir(HTTP_DIR + 'errors', options[:dry])
74
+ copy(dir + '/nginx.conf', CONFIG_DIR, options[:dry])
75
+
76
+ copy(dir + '/servers-lmm', CONFIG_DIR, options['dry'])
77
+ mkdir(WWW_DIR + 'root', options[:dry])
78
+ mkdir(WWW_DIR + 'errors', options[:dry])
79
+
80
+ template = ERB.new(File.read(__dir__ + '/main.conf.erb'))
81
+ renderTemplate(template, target, dir + 'main.conf', options)
82
+ copy(dir + '/main.conf', CONFIG_DIR, options[:dry])
83
+
84
+ dir = "/etc/letsencrypt/live/Wildcard/"
85
+ `mkdir -p #{dir}`
86
+ if !File.exist?(dir + 'fullchain.pem')
87
+ `openssl req -x509 -noenc -days 90 -newkey rsa:2048 -keyout #{dir}privkey.pem -out #{dir}fullchain.pem -subj "/C=US/O=ConfigLMM/CN=Wildcard"`
88
+ `cp #{dir}fullchain.pem #{dir}chain.pem`
89
+ end
90
+
35
91
  end
36
92
  # Consider:
37
93
  # * Deploy on current host
@@ -42,18 +98,23 @@ module ConfigLMM
42
98
  end
43
99
 
44
100
  def actionNginxProxyBuild(id, target, activeState, context, options)
45
- updateTargetConfig(target)
46
-
47
- template = ERB.new(File.read(__dir__ + '/proxy.conf.erb'))
48
- renderTemplate(template, target, options['output'] + '/nginx/servers-lmm/' + target['Name'] + '.conf', options)
49
-
101
+ target['ConfigName'] = target['Name']
102
+ writeNginxConfig(__dir__, 'proxy', id, target, activeState, context, options)
50
103
  actionNginxBuild(id, target, activeState, context, options)
51
104
  end
52
105
 
53
106
  def actionNginxProxyDeploy(id, target, activeState, context, options)
54
- if !target['Location'] || target['Location'] == '@me'
55
- deployNginxConfig(id, target, activeState, context, options)
56
- activeState['Location'] = '@me'
107
+ raise Framework::PluginProcessError.new('Proxy field must be set!') unless target['Proxy']
108
+
109
+ target['ConfigName'] = target['Name']
110
+ if target['Location'] && target['Location'] != '@me'
111
+ uri = Addressable::URI.parse(target['Location'])
112
+ raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
113
+ self.class.sshStart(uri) do |ssh|
114
+ useNginxProxy(__dir__, 'proxy', id, target, activeState, state, context, options, ssh)
115
+ end
116
+ else
117
+ useNginxProxy(__dir__, 'proxy', id, target, activeState, state, context, options, ssh)
57
118
  end
58
119
  end
59
120
 
@@ -6,9 +6,18 @@ server {
6
6
  listen <%= config['Port'] %>;
7
7
  listen [::]:<%= config['Port'] %>;
8
8
  <% else %>
9
- listen <%= config['Port'] %> ssl;
10
- listen [::]:<%= config['Port'] %> ssl;
11
- http2 on;
9
+ <% if config['NginxVersion'] >= 1.25 %>
10
+ listen <%= config['Port'] %> ssl;
11
+ listen [::]:<%= config['Port'] %> ssl;
12
+ http2 on;
13
+ http3 on;
14
+ quic_retry on;
15
+ add_header Alt-Svc 'h3=":<%= config['Port'] %>"; ma=86400';
16
+ <% else %>
17
+ listen <%= config['Port'] %> ssl http2;
18
+ listen [::]:<%= config['Port'] %> ssl http2;
19
+ <% end %>
20
+
12
21
  include config-lmm/ssl.conf;
13
22
  <% end %>
14
23
 
@@ -18,6 +27,7 @@ server {
18
27
  error_log /var/log/nginx/<%= config['Name'].downcase %>.error.log;
19
28
 
20
29
  include config-lmm/errors.conf;
30
+ include config-lmm/security.conf;
21
31
 
22
32
  <% if config['Private'] %>
23
33
  include config-lmm/private.conf;