ConfigLMM 0.3.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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/Plugins/Apps/Authentik/Authentik-ProxyOutpost.container +14 -0
  4. data/Plugins/Apps/Authentik/Authentik-Server.container +1 -0
  5. data/Plugins/Apps/Authentik/Authentik-Worker.container +1 -0
  6. data/Plugins/Apps/Authentik/Authentik.conf.erb +7 -0
  7. data/Plugins/Apps/Authentik/Authentik.lmm.rb +24 -2
  8. data/Plugins/Apps/BookStack/BookStack.conf.erb +41 -0
  9. data/Plugins/Apps/BookStack/BookStack.container +15 -0
  10. data/Plugins/Apps/BookStack/BookStack.lmm.rb +80 -0
  11. data/Plugins/Apps/Discourse/Discourse-Sidekiq.container +17 -0
  12. data/Plugins/Apps/Discourse/Discourse.conf.erb +41 -0
  13. data/Plugins/Apps/Discourse/Discourse.container +17 -0
  14. data/Plugins/Apps/Discourse/Discourse.lmm.rb +95 -0
  15. data/Plugins/Apps/Dovecot/Dovecot.lmm.rb +25 -2
  16. data/Plugins/Apps/ERPNext/ERPNext-Frontend.container +19 -0
  17. data/Plugins/Apps/ERPNext/ERPNext-Queue.container +17 -0
  18. data/Plugins/Apps/ERPNext/ERPNext-Scheduler.container +17 -0
  19. data/Plugins/Apps/ERPNext/ERPNext-Websocket.container +19 -0
  20. data/Plugins/Apps/ERPNext/ERPNext.container +18 -0
  21. data/Plugins/Apps/ERPNext/ERPNext.lmm.rb +193 -0
  22. data/Plugins/Apps/ERPNext/ERPNext.network +12 -0
  23. data/Plugins/Apps/ERPNext/sites/apps.json +10 -0
  24. data/Plugins/Apps/ERPNext/sites/apps.txt +3 -0
  25. data/Plugins/Apps/ERPNext/sites/common_site_config.json +11 -0
  26. data/Plugins/Apps/GitLab/GitLab.container +3 -2
  27. data/Plugins/Apps/GitLab/GitLab.lmm.rb +37 -12
  28. data/Plugins/Apps/LetsEncrypt/LetsEncrypt.lmm.rb +57 -0
  29. data/Plugins/Apps/LetsEncrypt/hooks/dovecot.sh +2 -0
  30. data/Plugins/Apps/LetsEncrypt/hooks/nginx.sh +2 -0
  31. data/Plugins/Apps/LetsEncrypt/hooks/postfix.sh +2 -0
  32. data/Plugins/Apps/LetsEncrypt/renew-certificates.service +7 -0
  33. data/Plugins/Apps/LetsEncrypt/renew-certificates.timer +12 -0
  34. data/Plugins/Apps/LetsEncrypt/rfc2136.ini +11 -0
  35. data/Plugins/Apps/MariaDB/MariaDB.lmm.rb +115 -0
  36. data/Plugins/Apps/Matrix/Element.container +14 -0
  37. data/Plugins/Apps/Matrix/Matrix.conf.erb +49 -5
  38. data/Plugins/Apps/Matrix/Matrix.lmm.rb +86 -1
  39. data/Plugins/Apps/Matrix/Synapse.container +17 -0
  40. data/Plugins/Apps/Matrix/config.json +50 -0
  41. data/Plugins/Apps/Matrix/homeserver.yaml +70 -0
  42. data/Plugins/Apps/Matrix/log.config +30 -0
  43. data/Plugins/Apps/Nextcloud/Nextcloud.lmm.rb +70 -45
  44. data/Plugins/Apps/Nginx/conf.d/configlmm.conf +9 -0
  45. data/Plugins/Apps/Nginx/config-lmm/errors.conf +10 -4
  46. data/Plugins/Apps/Nginx/config-lmm/proxy.conf +5 -1
  47. data/Plugins/Apps/Nginx/nginx.lmm.rb +15 -11
  48. data/Plugins/Apps/Nginx/proxy.conf.erb +13 -3
  49. data/Plugins/Apps/Odoo/Odoo.container +2 -1
  50. data/Plugins/Apps/Odoo/Odoo.lmm.rb +1 -1
  51. data/Plugins/Apps/OpenVidu/Ingress.container +18 -0
  52. data/Plugins/Apps/OpenVidu/OpenVidu.conf.erb +34 -0
  53. data/Plugins/Apps/OpenVidu/OpenVidu.container +16 -0
  54. data/Plugins/Apps/OpenVidu/OpenVidu.lmm.rb +90 -0
  55. data/Plugins/Apps/OpenVidu/OpenViduCall.conf.erb +35 -0
  56. data/Plugins/Apps/OpenVidu/OpenViduCall.container +15 -0
  57. data/Plugins/Apps/OpenVidu/ingress.yaml +10 -0
  58. data/Plugins/Apps/OpenVidu/livekit.yaml +13 -0
  59. data/Plugins/Apps/Peppermint/Peppermint.conf.erb +0 -4
  60. data/Plugins/Apps/Peppermint/Peppermint.container +2 -1
  61. data/Plugins/Apps/Postfix/Postfix.lmm.rb +32 -6
  62. data/Plugins/Apps/PostgreSQL/PostgreSQL.lmm.rb +80 -11
  63. data/Plugins/Apps/Roundcube/Roundcube.conf.erb +75 -0
  64. data/Plugins/Apps/Roundcube/Roundcube.lmm.rb +145 -0
  65. data/Plugins/Apps/Tunnel/tunnel.lmm.rb +63 -0
  66. data/Plugins/Apps/Tunnel/tunnelTCP.service +9 -0
  67. data/Plugins/Apps/Tunnel/tunnelTCP.socket +9 -0
  68. data/Plugins/Apps/Tunnel/tunnelUDP.service +9 -0
  69. data/Plugins/Apps/Tunnel/tunnelUDP.socket +9 -0
  70. data/Plugins/Apps/Valkey/Valkey.lmm.rb +32 -0
  71. data/Plugins/Apps/Vaultwarden/Vaultwarden.lmm.rb +4 -0
  72. data/Plugins/Apps/Wiki.js/Wiki.js.conf.erb +42 -0
  73. data/Plugins/Apps/Wiki.js/Wiki.js.container +15 -0
  74. data/Plugins/Apps/Wiki.js/Wiki.js.lmm.rb +61 -0
  75. data/Plugins/Apps/gollum/gollum.conf.erb +39 -1
  76. data/Plugins/Apps/gollum/gollum.container +4 -1
  77. data/Plugins/Apps/gollum/gollum.lmm.rb +11 -3
  78. data/Plugins/OS/Linux/Debian/preseed.cfg.erb +62 -0
  79. data/Plugins/OS/Linux/Distributions.yaml +32 -0
  80. data/Plugins/OS/Linux/Flavours.yaml +11 -0
  81. data/Plugins/OS/Linux/Linux.lmm.rb +255 -67
  82. data/Plugins/OS/Linux/Packages.yaml +47 -2
  83. data/Plugins/OS/Linux/Proxmox/answer.toml.erb +30 -0
  84. data/Plugins/OS/Linux/WireGuard/WireGuard.lmm.rb +33 -4
  85. data/Plugins/Platforms/GoDaddy/GoDaddy.lmm.rb +1 -1
  86. data/Plugins/Platforms/libvirt/libvirt.lmm.rb +3 -2
  87. data/Plugins/Services/DNS/PowerDNS.lmm.rb +95 -8
  88. data/bootstrap.sh +41 -3
  89. data/lib/ConfigLMM/Framework/plugins/linuxApp.rb +146 -64
  90. data/lib/ConfigLMM/Framework/plugins/nginxApp.rb +34 -3
  91. data/lib/ConfigLMM/Framework/plugins/plugin.rb +62 -6
  92. data/lib/ConfigLMM/cli.rb +3 -1
  93. data/lib/ConfigLMM/commands/cleanup.rb +1 -0
  94. data/lib/ConfigLMM/commands/configsCommand.rb +3 -1
  95. data/lib/ConfigLMM/io/configList.rb +3 -1
  96. data/lib/ConfigLMM/state.rb +10 -2
  97. data/lib/ConfigLMM/version.rb +1 -1
  98. metadata +54 -3
  99. data/Plugins/Apps/GitLab/GitLab.conf.erb +0 -26
@@ -0,0 +1,145 @@
1
+
2
+ module ConfigLMM
3
+ module LMM
4
+ class Roundcube < Framework::NginxApp
5
+
6
+ USER = 'roundcube'
7
+ HOME_DIR = '/var/lib/roundcube'
8
+ PACKAGE_NAME = 'Roundcube'
9
+
10
+ def actionRoundcubeDeploy(id, target, activeState, context, options)
11
+ raise Framework::PluginProcessError.new('Domain field must be set!') unless target['Domain']
12
+
13
+ target['Database'] ||= {}
14
+ if target['Location'] && target['Location'] != '@me'
15
+ uri = Addressable::URI.parse(target['Location'])
16
+ raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
17
+
18
+ self.class.sshStart(uri) do |ssh|
19
+
20
+ Framework::LinuxApp.ensurePackages([PHP_FPM::PHPFPM_PACKAGE], ssh)
21
+ Framework::LinuxApp.ensureServiceAutoStartOverSSH(PHP_FPM::PHPFPM_SERVICE, ssh)
22
+ distroInfo = Framework::LinuxApp.ensurePackages([PACKAGE_NAME], ssh)
23
+ addUserCmd = "#{distroInfo['CreateServiceUser']} --home-dir '#{HOME_DIR}' --create-home --comment 'Roundcube' #{USER}"
24
+ self.class.exec(addUserCmd, ssh, true)
25
+ self.class.exec("chmod o-rwx #{HOME_DIR}", ssh)
26
+
27
+ self.class.exec("touch /var/log/php/roundcube.errors.log", ssh)
28
+ self.class.exec("touch /var/log/php/roundcube.mail.log", ssh)
29
+ self.class.exec("chown #{USER}:#{USER} /var/log/php/roundcube.errors.log", ssh)
30
+ self.class.exec("chown #{USER}:#{USER} /var/log/php/roundcube.mail.log", ssh)
31
+ self.class.exec("chown -R #{USER}:#{USER} /var/log/roundcubemail /var/lib/roundcubemail", ssh)
32
+ PHP_FPM::fixConfigFileOverSSH(distroInfo, ssh)
33
+
34
+ roundcubeBaseDir = '/usr/share/webapps/roundcubemail'
35
+ if distroInfo['Name'] == 'openSUSE Leap'
36
+ roundcubeBaseDir = '/srv/www/roundcubemail'
37
+ end
38
+
39
+ self.class.exec("sed -i 's|$config\\[\\'des_key\\'\\].*|$config\\[\\'des_key\\'\\] = \\'#{SecureRandom.alphanumeric(24)}\\';|' #{roundcubeBaseDir}/config/config.inc.php", ssh)
40
+ self.class.exec("sed -i 's|$config\\[\\'product_name\\'\\].*|$config\\[\\'product_name\\'\\] = \\'Webmail\\';|' #{roundcubeBaseDir}/config/config.inc.php", ssh)
41
+
42
+ if target['IMAP']['Host']
43
+ protocol = ''
44
+ if target['IMAP']['Port'] == 993
45
+ protocol = 'ssl://'
46
+ end
47
+ self.class.exec("sed -i 's|$config\\[\\'imap_host\\'\\].*|$config\\[\\'imap_host\\'\\] = \\'#{protocol}#{target['IMAP']['Host']}:#{target['IMAP']['Port']}\\';|' #{roundcubeBaseDir}/config/config.inc.php", ssh)
48
+ end
49
+
50
+ if target['SMTP']['Host']
51
+ protocol = ''
52
+ if target['SMTP']['Port'] == 465
53
+ protocol = 'ssl://'
54
+ end
55
+ self.class.exec("sed -i 's|$config\\[\\'smtp_host\\'\\].*|$config\\[\\'smtp_host\\'\\] = \\'#{protocol}#{target['SMTP']['Host']}:#{target['SMTP']['Port']}\\';|' #{roundcubeBaseDir}/config/config.inc.php", ssh)
56
+ end
57
+
58
+ target['Database'] ||= {}
59
+ activeState['Database'] = target['Database']
60
+ if !target['Database']['Type'] || target['Database']['Type'] == 'pgsql'
61
+ password = SecureRandom.alphanumeric(20)
62
+ PostgreSQL.createRemoteUserAndDBOverSSH(target['Database'], USER, password, ssh)
63
+ self.class.exec("sed -i 's|$config\\[\\'db_dsnw\\'\\].*|$config\\[\\'db_dsnw\\'\\] = \\'pgsql://#{USER}:#{password}@#{target['Database']['HostName']}/#{USER}\\';|' #{roundcubeBaseDir}/config/config.inc.php", ssh)
64
+ end
65
+
66
+ self.updateRemoteFile(ssh, roundcubeBaseDir + '/config/config.inc.php', options, false, '//') do |configLines|
67
+ if target['Settings']
68
+ target['Settings'].each do |name, value|
69
+ configLines << "$config['#{name}'] = '#{value}';\n"
70
+ end
71
+ end
72
+ configLines << "$config['login_lc'] = 0;\n"
73
+ configLines << "$config['enable_installer'] = true;\n"
74
+ end
75
+
76
+ target['User'] = USER unless target['User']
77
+ name = 'roundcube'
78
+ target['PHP-FPM'] ||= {}
79
+ if distroInfo['Name'] == 'openSUSE Leap'
80
+ target['PHP-FPM']['chdir'] = roundcubeBaseDir
81
+ end
82
+ self.updateRemoteFile(ssh, PHP_FPM.configDir(distroInfo) + name + '.conf', options, false, ';') do |configLines|
83
+ PHP_FPM.writeConfig(name, target, distroInfo, configLines)
84
+ end
85
+
86
+ Framework::LinuxApp.startServiceOverSSH(PHP_FPM::PHPFPM_SERVICE, ssh)
87
+
88
+ if !target.key?('Proxy') || target['Proxy']
89
+ self.class.ensurePackage(ssh)
90
+ self.class.prepareNginxConfig(target, ssh)
91
+ self.writeNginxConfig(__dir__, 'Roundcube', id, target, state, context, options)
92
+ if distroInfo['Name'] == 'openSUSE Leap'
93
+ nginxFile = options['output'] + '/nginx/servers-lmm/Roundcube.conf'
94
+ `sed -i 's|root .*|root #{roundcubeBaseDir}/public_html;|' #{nginxFile}`
95
+ end
96
+ self.deployNginxConfig(id, target, activeState, context, options)
97
+ Framework::LinuxApp.startServiceOverSSH(NGINX_PACKAGE, ssh)
98
+ self.class.reload(ssh)
99
+ end
100
+
101
+ self.class.exec("curl 'https://#{target['Domain']}/installer/index.php?_step=3' -X POST --data-raw 'initdb=Initialize+database'", ssh)
102
+ self.class.exec("rm -f #{roundcubeBaseDir}/public_html/installer", ssh)
103
+ self.class.exec("sed -i 's|$config\\[\\'enable_installer\\'\\].*|$config\\[\\'enable_installer\\'\\] = false;|' #{roundcubeBaseDir}/config/config.inc.php", ssh)
104
+ end
105
+ else
106
+ # TODO
107
+ end
108
+ activeState['Status'] = State::STATUS_DEPLOYED
109
+ end
110
+
111
+ def cleanup(configs, state, context, options)
112
+ cleanupType(:Roundcube, configs, state, context, options) do |item, id, state, context, options, ssh|
113
+ cleanupConfig(item, id, state, context, options, ssh)
114
+ end
115
+ end
116
+
117
+ def cleanupConfig(item, id, state, context, options, ssh = nil)
118
+ if item['Proxy'].nil? || item['Proxy']
119
+ self.cleanupNginxConfig('Roundcube', id, state, context, options, ssh)
120
+ self.class.reload(ssh, options[:dry])
121
+ end
122
+ distroInfo = Framework::LinuxApp.currentDistroInfo(ssh)
123
+ rm(PHP_FPM.configDir(distroInfo) + 'roundcube.conf', options[:dry], ssh)
124
+ Framework::LinuxApp.reloadService(PHP_FPM::PHPFPM_SERVICE, ssh, options[:dry])
125
+ Framework::LinuxApp.removePackage(PACKAGE_NAME, ssh, options[:dry])
126
+ state.item(id)['Status'] = State::STATUS_DELETED unless options[:dry]
127
+ if options[:destroy]
128
+ item['Database'] ||= {}
129
+ if !item['Database']['Type'] || item['Database']['Type'] == 'pgsql'
130
+ PostgreSQL.dropUserAndDB(item['Database'], USER, ssh, options[:dry])
131
+ end
132
+ Framework::LinuxApp.deleteUserAndGroup(USER, ssh, options[:dry])
133
+ rm('/var/log/roundcubemail', options[:dry], ssh)
134
+ rm('/var/log/php/roundcube.access.log', options[:dry], ssh)
135
+ rm('/var/log/php/roundcube.errors.log', options[:dry], ssh)
136
+ rm('/var/log/php/roundcube.mail.log', options[:dry], ssh)
137
+ rm('/var/log/nginx/roundcube.access.log', options[:dry], ssh)
138
+ rm('/var/log/nginx/roundcube.error.log', options[:dry], ssh)
139
+ state.item(id)['Status'] = State::STATUS_DESTROYED unless options[:dry]
140
+ end
141
+ end
142
+
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,63 @@
1
+
2
+ module ConfigLMM
3
+ module LMM
4
+ class Tunnel < Framework::NginxApp
5
+
6
+ def actionTunnelDeploy(id, target, activeState, context, options)
7
+
8
+ if target['Location'] && target['Location'] != '@me'
9
+ uri = Addressable::URI.parse(target['Location'])
10
+ raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
11
+
12
+ self.class.sshStart(uri) do |ssh|
13
+
14
+ Framework::LinuxApp.ensurePackage('socat', ssh)
15
+
16
+ port = target['Port']
17
+ activeState['Port'] = port
18
+ activeState['UDP'] = target['UDP']
19
+ if target['UDP']
20
+ name = "tunnelUDP-#{port}"
21
+ ssh.scp.upload!(__dir__ + '/tunnelUDP.service', "/etc/systemd/system/#{name}.service")
22
+ ssh.scp.upload!(__dir__ + '/tunnelUDP.socket', "/etc/systemd/system/#{name}.socket")
23
+ self.class.exec("sed -i 's|$PORT|#{port}|' /etc/systemd/system/#{name}.service", ssh)
24
+ self.class.exec("sed -i 's|$PORT|#{port}|' /etc/systemd/system/#{name}.socket", ssh)
25
+ self.class.exec("sed -i 's|$REMOTE|#{target['Remote']}|' /etc/systemd/system/#{name}.service", ssh)
26
+ else
27
+ name = "tunnelTCP-#{port}"
28
+ ssh.scp.upload!(__dir__ + '/tunnelTCP.service', "/etc/systemd/system/#{name}.service")
29
+ ssh.scp.upload!(__dir__ + '/tunnelTCP.socket', "/etc/systemd/system/#{name}.socket")
30
+ self.class.exec("sed -i 's|$PORT|#{port}|' /etc/systemd/system/#{name}.service", ssh)
31
+ self.class.exec("sed -i 's|$PORT|#{port}|' /etc/systemd/system/#{name}.socket", ssh)
32
+ self.class.exec("sed -i 's|$REMOTE|#{target['Remote']}|' /etc/systemd/system/#{name}.service", ssh)
33
+ end
34
+
35
+ Framework::LinuxApp.reloadServiceManager(ssh)
36
+ Framework::LinuxApp.ensureServiceAutoStart(name + '.socket', ssh)
37
+ Framework::LinuxApp.stopService(name + '.service', ssh)
38
+ Framework::LinuxApp.startService(name + '.socket', ssh)
39
+ end
40
+ else
41
+ # TODO
42
+ end
43
+ activeState['Status'] = State::STATUS_DEPLOYED
44
+ end
45
+
46
+ def cleanup(configs, state, context, options)
47
+ cleanupType(:Tunnel, configs, state, context, options) do |item, id, state, context, options, ssh|
48
+ if item['UDP']
49
+ name = "tunnelUDP-#{item['Port']}"
50
+ else
51
+ name = "tunnelTCP-#{item['Port']}"
52
+ end
53
+ Framework::LinuxApp.stopService(name + '.socket', ssh)
54
+ Framework::LinuxApp.disableService(name + '.socket', ssh)
55
+ rm("/etc/systemd/system/#{name}.service", options[:dry], ssh)
56
+ rm("/etc/systemd/system/#{name}.socket", options[:dry], ssh)
57
+ state.item(id)['Status'] = State::STATUS_DESTROYED
58
+ end
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,9 @@
1
+
2
+ [Unit]
3
+ Description=Forward TCP $PORT to remote
4
+
5
+ [Service]
6
+ ExecStart=/usr/lib/systemd/systemd-socket-proxyd $REMOTE
7
+
8
+ [Install]
9
+ WantedBy=multi-user.target
@@ -0,0 +1,9 @@
1
+
2
+ [Unit]
3
+ Description=TCP tunnel listening on local port $PORT
4
+
5
+ [Socket]
6
+ ListenStream=$PORT
7
+
8
+ [Install]
9
+ WantedBy=sockets.target
@@ -0,0 +1,9 @@
1
+
2
+ [Unit]
3
+ Description=Forward UDP $PORT to remote
4
+
5
+ [Service]
6
+ ExecStart=/usr/bin/socat UDP-RECVFROM:$PORT,reuseaddr,fork UDP-SENDTO:$REMOTE
7
+
8
+ [Install]
9
+ WantedBy=multi-user.target
@@ -0,0 +1,9 @@
1
+
2
+ [Unit]
3
+ Description=UDP tunnel listening on local port $PORT
4
+
5
+ [Socket]
6
+ ListenDatagram=$PORT
7
+
8
+ [Install]
9
+ WantedBy=sockets.target
@@ -24,6 +24,12 @@ module ConfigLMM
24
24
  target['Settings']['dir'] = '/var/lib/redis/default/'
25
25
  end
26
26
 
27
+ if ENV[id + '-VALKEY_PASSWORD']
28
+ target['Settings']['requirepass'] = ENV[id + '-VALKEY_PASSWORD']
29
+ elsif ENV['VALKEY_PASSWORD']
30
+ target['Settings']['requirepass'] = ENV['VALKEY_PASSWORD']
31
+ end
32
+
27
33
  if target['Settings']
28
34
  target['Settings']['bind'] = '127.0.0.1' unless target['Settings']['bind']
29
35
  updateRemoteFile(ssh, CONFIG_FILE, options, false) do |configLines|
@@ -33,6 +39,9 @@ module ConfigLMM
33
39
  configLines
34
40
  end
35
41
  end
42
+
43
+ self.class.exec("chgrp redis #{CONFIG_FILE}", ssh)
44
+ self.class.exec("chmod 640 #{CONFIG_FILE}", ssh)
36
45
  end
37
46
  else
38
47
  if target['Settings']
@@ -44,10 +53,33 @@ module ConfigLMM
44
53
  configLines
45
54
  end
46
55
  end
56
+ self.class.exec("chgrp redis #{CONFIG_FILE}", ssh)
57
+ self.class.exec("chmod 640 #{CONFIG_FILE}", nil)
47
58
  end
48
59
 
49
60
  self.ensureServiceAutoStart(serviceName, target['Location'])
50
61
  self.startService(serviceName, target['Location'])
62
+
63
+ activeState['Status'] = State::STATUS_DEPLOYED
64
+ end
65
+
66
+ def cleanup(configs, state, context, options)
67
+ cleanupType(:Valkey, configs, state, context, options) do |item, id, state, context, options, ssh|
68
+ serviceName = 'redis'
69
+ distroId = self.class.distroID(ssh)
70
+ serviceName = 'redis@redis' if distroId == SUSE_ID
71
+
72
+ Framework::LinuxApp.stopService(serviceName, ssh, options[:dry])
73
+ Framework::LinuxApp.removePackage(PACKAGE_NAME, ssh, options[:dry])
74
+
75
+ state.item(id)['Status'] = State::STATUS_DELETED unless options[:dry]
76
+
77
+ if options[:destroy]
78
+ rm('/etc/redis', options[:dry], ssh)
79
+
80
+ state.item(id)['Status'] = State::STATUS_DESTROYED unless options[:dry]
81
+ end
82
+ end
51
83
  end
52
84
 
53
85
  end
@@ -8,6 +8,7 @@ module ConfigLMM
8
8
  NAME = 'Vaultwarden'
9
9
  USER = 'vaultwarden'
10
10
  HOME_DIR = '/var/lib/vaultwarden'
11
+ SERVICE_PORT = '18000'
11
12
 
12
13
  def actionVaultwardenBuild(id, target, state, context, options)
13
14
  writeNginxConfig(__dir__, NAME, id, target, state, context, options)
@@ -46,6 +47,9 @@ module ConfigLMM
46
47
  ssh.scp.upload!(__dir__ + '/Vaultwarden.container', path)
47
48
  self.class.sshExec!(ssh, "systemctl --user --machine=#{USER}@ daemon-reload")
48
49
  self.class.sshExec!(ssh, "systemctl --user --machine=#{USER}@ start Vaultwarden")
50
+ if target['Proxy'] != 'only'
51
+ Framework::LinuxApp.firewallAddPortOverSSH(SERVICE_PORT + '/tcp', ssh)
52
+ end
49
53
  end
50
54
  if !target.key?('Proxy') || !!target['Proxy']
51
55
  self.class.prepareNginxConfig(target, ssh)
@@ -0,0 +1,42 @@
1
+
2
+ server {
3
+
4
+ <% if !config['TLS'] %>
5
+ listen <%= config['Port'] %>;
6
+ listen [::]:<%= config['Port'] %>;
7
+ <% else %>
8
+ <% if config['NginxVersion'] >= 1.25 %>
9
+ listen <%= config['Port'] %> ssl;
10
+ listen [::]:<%= config['Port'] %> ssl;
11
+ http2 on;
12
+ http3 on;
13
+ quic_retry on;
14
+ add_header Alt-Svc 'h3=":<%= config['Port'] %>"; ma=86400';
15
+ <% else %>
16
+ listen <%= config['Port'] %> ssl http2;
17
+ listen [::]:<%= config['Port'] %> ssl http2;
18
+ <% end %>
19
+
20
+ include config-lmm/ssl.conf;
21
+ <% end %>
22
+
23
+ server_name <%= config['Domain'] %>;
24
+
25
+ access_log /var/log/nginx/wikijs.access.log;
26
+ error_log /var/log/nginx/wikijs.error.log;
27
+
28
+ include config-lmm/errors.conf;
29
+ include config-lmm/security.conf;
30
+
31
+ location / {
32
+ <% if config['Server'] %>
33
+ proxy_pass <%= config['Server'] %>;
34
+ <% else %>
35
+ proxy_pass http://127.0.0.1:13200;
36
+ <% end %>
37
+
38
+ include config-lmm/proxy.conf;
39
+ }
40
+
41
+ }
42
+
@@ -0,0 +1,15 @@
1
+
2
+ [Unit]
3
+ Description=Wiki.js container
4
+ After=local-fs.target
5
+
6
+ [Container]
7
+ Image=docker.io/requarks/wiki:latest
8
+ EnvironmentFile=/var/lib/wikijs/.config/containers/systemd/Wiki.js.env
9
+ Network=slirp4netns:allow_host_loopback=true
10
+ PublishPort=127.0.0.1:13200:3000
11
+ UserNS=keep-id:uid=1000,gid=1000
12
+ AutoUpdate=registry
13
+
14
+ [Install]
15
+ WantedBy=multi-user.target default.target
@@ -0,0 +1,61 @@
1
+
2
+ module ConfigLMM
3
+ module LMM
4
+ class WikiJS < Framework::NginxApp
5
+
6
+ USER = 'wikijs'
7
+ HOME_DIR = '/var/lib/wikijs'
8
+ HOST_IP = '10.0.2.2'
9
+
10
+ def actionWikiJSDeploy(id, target, activeState, context, options)
11
+ raise Framework::PluginProcessError.new('Domain field must be set!') unless target['Domain']
12
+
13
+ target['Database'] ||= {}
14
+ if target['Location'] && target['Location'] != '@me'
15
+ uri = Addressable::URI.parse(target['Location'])
16
+ raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
17
+
18
+ self.class.sshStart(uri) do |ssh|
19
+
20
+ dbPassword = self.configurePostgreSQL(target['Database'], ssh)
21
+ distroInfo = Framework::LinuxApp.currentDistroInfo(ssh)
22
+ Framework::LinuxApp.configurePodmanServiceOverSSH(USER, HOME_DIR, 'Wiki.js', distroInfo, ssh)
23
+
24
+ path = Framework::LinuxApp::SYSTEMD_CONTAINERS_PATH.gsub('~', HOME_DIR)
25
+ self.class.exec("echo 'DB_TYPE=postgres' > #{path}/Wiki.js.env", ssh)
26
+ self.class.exec("echo 'DB_HOST=#{HOST_IP}' >> #{path}/Wiki.js.env", ssh)
27
+ self.class.exec("echo 'DB_PORT=5432' >> #{path}/Wiki.js.env", ssh)
28
+ self.class.exec("echo 'DB_USER=#{USER}' >> #{path}/Wiki.js.env", ssh)
29
+ self.class.exec("echo 'DB_NAME=#{USER}' >> #{path}/Wiki.js.env", ssh)
30
+ self.class.exec(" echo 'DB_PASS=#{dbPassword}' >> #{path}/Wiki.js.env", ssh)
31
+
32
+ self.class.exec("chown #{USER}:#{USER} #{path}/Wiki.js.env", ssh)
33
+ self.class.exec("chmod 600 #{path}/Wiki.js.env", ssh)
34
+
35
+ ssh.scp.upload!(__dir__ + '/Wiki.js.container', path)
36
+ self.class.exec("systemctl --user --machine=#{USER}@ daemon-reload", ssh)
37
+ self.class.exec("systemctl --user --machine=#{USER}@ restart Wiki.js", ssh)
38
+
39
+ Framework::LinuxApp.ensurePackages([NGINX_PACKAGE], ssh)
40
+ Framework::LinuxApp.ensureServiceAutoStartOverSSH(NGINX_PACKAGE, ssh)
41
+ self.class.prepareNginxConfig(target, ssh)
42
+ self.writeNginxConfig(__dir__, 'Wiki.js', id, target, state, context, options)
43
+ self.deployNginxConfig(id, target, activeState, context, options)
44
+ Framework::LinuxApp.startServiceOverSSH(NGINX_PACKAGE, ssh)
45
+
46
+ end
47
+ else
48
+ # TODO
49
+ end
50
+ end
51
+
52
+ def configurePostgreSQL(settings, ssh)
53
+ password = SecureRandom.alphanumeric(20)
54
+ PostgreSQL.createRemoteUserAndDBOverSSH(settings, USER, password, ssh)
55
+ password
56
+ end
57
+
58
+ end
59
+ end
60
+ end
61
+
@@ -36,7 +36,10 @@ server {
36
36
  access_log /var/log/nginx/gollum.access.log;
37
37
  error_log /var/log/nginx/gollum.error.log;
38
38
 
39
- include config-lmm/private.conf;
39
+ <% if config['AuthentikDomain'].nil? %>
40
+ include config-lmm/private.conf;
41
+ <% end %>
42
+
40
43
  include config-lmm/errors.conf;
41
44
 
42
45
  <% if config['CertName'] %>
@@ -62,7 +65,42 @@ server {
62
65
  location / {
63
66
  proxy_pass <%= config['Server'] %>;
64
67
 
68
+ <% if config['AuthentikDomain'] %>
69
+ error_page 401 = @authenticate;
70
+ include config-lmm/errors.conf;
71
+
72
+ auth_request /outpost.goauthentik.io/auth/nginx;
73
+
74
+ # translate headers from the outposts back to the actual upstream
75
+ auth_request_set $authentik_username $upstream_http_x_authentik_username;
76
+ auth_request_set $authentik_groups $upstream_http_x_authentik_groups;
77
+ auth_request_set $authentik_email $upstream_http_x_authentik_email;
78
+ auth_request_set $authentik_name $upstream_http_x_authentik_name;
79
+ auth_request_set $authentik_uid $upstream_http_x_authentik_uid;
80
+
81
+ proxy_set_header REMOTE_USER $authentik_username;
82
+ proxy_set_header REMOTE_GROUPS $authentik_groups;
83
+ proxy_set_header REMOTE_EMAIL $authentik_email;
84
+ proxy_set_header REMOTE_NAME $authentik_name;
85
+ proxy_set_header REMOTE_UID $authentik_uid;
86
+ <% end %>
87
+
65
88
  include config-lmm/proxy.conf;
66
89
  }
67
90
  <% end %>
91
+
92
+ <% if config['AuthentikDomain'] %>
93
+ location /outpost.goauthentik.io {
94
+ proxy_pass https://<%= config['AuthentikDomain'] %>/outpost.goauthentik.io;
95
+ proxy_ssl_protocols TLSv1.2 TLSv1.3;
96
+ proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
97
+ proxy_pass_request_body off;
98
+ proxy_set_header Content-Length "";
99
+ }
100
+
101
+ location @authenticate {
102
+ internal;
103
+ return 302 /outpost.goauthentik.io/start?rd=$request_uri;
104
+ }
105
+ <% end %>
68
106
  }
@@ -3,10 +3,13 @@ Description=gollum container
3
3
  After=local-fs.target
4
4
 
5
5
  [Container]
6
- Image=gollumwiki/gollum:master
6
+ Image=docker.io/gollumwiki/gollum:master
7
+ Exec=--config=/config/config.rb
7
8
  PublishPort=0.0.0.0:14567:4567
8
9
  UserNS=keep-id:uid=1000,gid=1000
9
10
  Volume=/srv/gollum/repo:/wiki
11
+ Volume=/srv/gollum/config:/config
12
+ AutoUpdate=registry
10
13
 
11
14
  [Install]
12
15
  WantedBy=multi-user.target default.target
@@ -6,12 +6,12 @@ module ConfigLMM
6
6
  NAME = 'gollum'
7
7
  USER = 'gollum'
8
8
  GOLLUM_PATH = '/srv/gollum'
9
- HOME_DIR = '/var/lib/authentik'
9
+ GOLLUM_PORT = '14567'
10
10
 
11
11
  def actionGollumBuild(id, target, activeState, context, options)
12
12
  writeNginxConfig(__dir__, NAME, id, target, activeState, context, options)
13
13
  targetDir = options['output'] + GOLLUM_PATH
14
- mkdir(targetDir, options['dry'])
14
+ mkdir(targetDir + '/config', options['dry'])
15
15
  copy(__dir__ + '/config.ru', targetDir, options['dry'])
16
16
  `git init #{targetDir}/repo`
17
17
  end
@@ -36,12 +36,20 @@ module ConfigLMM
36
36
  if !target.key?('Proxy') || target['Proxy'] != 'only'
37
37
  distroInfo = Framework::LinuxApp.currentDistroInfo(ssh)
38
38
  Framework::LinuxApp.configurePodmanServiceOverSSH(USER, GOLLUM_PATH, 'gollum', distroInfo, ssh)
39
+ if target['Config']
40
+ `cp #{target['Config']} #{options['output'] + GOLLUM_PATH}/config/config.rb`
41
+ else
42
+ `touch #{options['output'] + GOLLUM_PATH}/config/config.rb`
43
+ end
39
44
  self.class.uploadFolder(options['output'] + GOLLUM_PATH, '/srv', ssh)
40
45
  path = Framework::LinuxApp::SYSTEMD_CONTAINERS_PATH.gsub('~', GOLLUM_PATH)
41
46
  ssh.scp.upload!(__dir__ + '/gollum.container', path)
42
47
  self.class.sshExec!(ssh, "chown -R #{USER}:#{USER} #{GOLLUM_PATH}")
43
48
  self.class.sshExec!(ssh, "systemctl --user --machine=#{USER}@ daemon-reload")
44
- self.class.sshExec!(ssh, "systemctl --user --machine=#{USER}@ start gollum")
49
+ self.class.sshExec!(ssh, "systemctl --user --machine=#{USER}@ restart gollum")
50
+ if target['Proxy'] != 'only'
51
+ Framework::LinuxApp.firewallAddPortOverSSH(GOLLUM_PORT + '/tcp', ssh)
52
+ end
45
53
  end
46
54
  end
47
55
  else
@@ -0,0 +1,62 @@
1
+ #_preseed_V1
2
+
3
+ d-i debian-installer/locale string en_US
4
+ d-i keyboard-configuration/xkb-keymap select us
5
+
6
+ <% if config['Network'].is_a?(Hash) %>
7
+ d-i netcfg/disable_autoconfig boolean true
8
+ d-i netcfg/dhcp_failed note
9
+ d-i netcfg/dhcp_options select Configure network manually
10
+
11
+ d-i netcfg/get_ipaddress string <%= config['Network']['IP'].split('/').first %>
12
+ d-i netcfg/get_netmask string <%= [((1 << 32) - 1) << (32 - config['Network']['IP'].split('/').last.to_i)].pack('N').bytes.join('.') %>
13
+ d-i netcfg/get_gateway string <%= config['Network']['Gateway'] %>
14
+ d-i netcfg/get_nameservers string <%= config['Network']['DNS'] %>
15
+ d-i netcfg/confirm_static boolean true
16
+ <% end %>
17
+
18
+ d-i netcfg/get_hostname string <%= Addressable::IDNA.to_ascii(config['Domain']) %>
19
+
20
+ d-i passwd/make-user boolean false
21
+
22
+ <% if config['Users'].to_h['root'].to_h['PasswordHash'] %>
23
+ d-i passwd/root-password-crypted password <%= config['Users']['root']['PasswordHash'] %>
24
+ <% elsif config['Users'].to_h['root'].to_h['Password'] %>
25
+ d-i passwd/root-password password <%= config['Users']['root']['Password'] %>
26
+ <% end %>
27
+
28
+ d-i time/zone string UTC
29
+
30
+ d-i partman-auto/method string regular
31
+ d-i partman-auto/choose_recipe select atomic
32
+ d-i partman/choose_partition select finish
33
+ d-i partman/confirm_nooverwrite boolean true
34
+
35
+ d-i base-installer/install-recommends boolean false
36
+ d-i apt-setup/cdrom/set-first boolean false
37
+ d-i apt-setup/non-free-firmware boolean true
38
+ d-i apt-setup/non-free boolean true
39
+ d-i apt-setup/contrib boolean true
40
+ d-i apt-setup/use_mirror boolean true
41
+ d-i mirror/country string US
42
+ d-i mirror/http/mirror select deb.debian.org
43
+ d-i mirror/http/proxy string
44
+
45
+ d-i pkgsel/run_tasksel boolean false
46
+
47
+ <% if !config['Apps'].to_a.empty? %>
48
+ d-i pkgsel/include string <%= config['Apps'].map(&:downcase).join(' ') %>
49
+ <% end %>
50
+
51
+ d-i pkgsel/upgrade select full-upgrade
52
+
53
+ popularity-contest popularity-contest/participate boolean false
54
+
55
+ d-i grub-installer/only_debian boolean true
56
+ d-i grub-installer/bootdev string default
57
+
58
+ d-i finish-install/reboot_in_progress note
59
+
60
+ <% if !config['Users'].to_h['root'].to_h['AuthorizedKeys'].empty? %>
61
+ d-i preseed/late_command string in-target sh -c "echo '<%= config['Users']['root']['AuthorizedKeys'].first %>' > /root/.ssh/authorized_keys"
62
+ <% end %>