mimas 0.1.1 → 0.2.1
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.
- checksums.yaml +4 -4
- data/lib/mimas/cli.rb +6 -1
- data/lib/mimas/deployment/caddy.rb +3 -2
- data/lib/mimas/plugins.rb +0 -3
- data/lib/mimas/ssh.rb +3 -3
- data/lib/mimas/template.rb +28 -7
- data/lib/mimas/templates/Caddyfile.static.erb +9 -0
- data/lib/mimas/templates/mimas.env.erb +1 -0
- data/lib/mimas/version.rb +1 -1
- data/lib/mimas.rb +4 -0
- metadata +3 -12
- data/.gitignore +0 -10
- data/Gemfile +0 -12
- data/Gemfile.lock +0 -106
- data/LICENSE.txt +0 -22
- data/README.md +0 -346
- data/Rakefile +0 -4
- data/mimas.gemspec +0 -29
- data/scripts/release +0 -8
- data/scripts/test +0 -7
- data/tmp/.keep +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bff9e2b2cc427f8ebf816f67196d59555ac655caf6567125e0470f95eac8f917
|
|
4
|
+
data.tar.gz: 9626638c071cb4e421b4a83a4ffbe925b82839de11eedf8e0f8fad44535c501a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d9e3063a17af40b512bd63e157c52e79814e3b6293be0ec21076f11ca747ad17f0ec0fa7d6787f1a942a16aaf26e189b37701cb00a7c07db386bf1735cd01295
|
|
7
|
+
data.tar.gz: 4f734fd9de7fd3004f9dc22b84eca996e3a6d81aecce96c3f6668fbc73cfca6281f3bceab6e2cd7c0be643d63134cbff48fcd0df8c453c50c8e52468ff566fce
|
data/lib/mimas/cli.rb
CHANGED
|
@@ -14,9 +14,14 @@ module Mimas
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
Plugins.fetch.each do |plugin|
|
|
17
|
+
# Register plugin commands
|
|
17
18
|
plugin.commands.each do |command, target|
|
|
18
19
|
CLI::Commands.register(command.to_s, target)
|
|
19
|
-
end
|
|
20
|
+
end if plugin.respond_to?(:commands)
|
|
21
|
+
|
|
22
|
+
# Add plugin template paths to lookup array
|
|
23
|
+
Mimas::Template.lookup_paths.unshift(Pathname.new(plugin.templates_dir.to_s)) \
|
|
24
|
+
if plugin.respond_to?(:templates_dir)
|
|
20
25
|
end
|
|
21
26
|
end
|
|
22
27
|
end
|
|
@@ -19,9 +19,10 @@ module Mimas
|
|
|
19
19
|
session.upload StringIO.new(caddyfile), new_caddyfile_path
|
|
20
20
|
session.run "caddy validate --config #{new_caddyfile_path}", capture: true
|
|
21
21
|
say "New Caddyfile validated"
|
|
22
|
-
rescue SSH::Session::NonZeroExitCode
|
|
22
|
+
rescue SSH::Session::NonZeroExitCode => e
|
|
23
23
|
session.run "rm #{new_caddyfile_path}"
|
|
24
|
-
say caddyfile.
|
|
24
|
+
say caddyfile.red
|
|
25
|
+
say e.output.bold.red
|
|
25
26
|
raise "Your Caddyfile is invalid"
|
|
26
27
|
end
|
|
27
28
|
end
|
data/lib/mimas/plugins.rb
CHANGED
data/lib/mimas/ssh.rb
CHANGED
|
@@ -35,12 +35,12 @@ module Mimas
|
|
|
35
35
|
status = {}
|
|
36
36
|
output = ""
|
|
37
37
|
@ssh.exec!(command, status: status) do |channel, stream, data|
|
|
38
|
-
if
|
|
38
|
+
if capture
|
|
39
39
|
output << data
|
|
40
40
|
elsif stream == :stderr
|
|
41
|
-
print "#{data}".bold.red
|
|
41
|
+
print "#{data}".bold.red
|
|
42
42
|
else
|
|
43
|
-
print "#{data}".white
|
|
43
|
+
print "#{data}".white
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
data/lib/mimas/template.rb
CHANGED
|
@@ -2,26 +2,47 @@ require "fileutils"
|
|
|
2
2
|
|
|
3
3
|
module Mimas
|
|
4
4
|
module Template
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def template(file_name, dir: BASE_DIRECTORY, **vars)
|
|
5
|
+
def template(file_name, dir: nil, **vars)
|
|
8
6
|
template = read_template(file_name, dir: dir)
|
|
9
7
|
template.result_with_hash(vars)
|
|
10
8
|
end
|
|
11
9
|
|
|
12
|
-
def read_file(file_name, dir:
|
|
13
|
-
|
|
10
|
+
def read_file(file_name, dir: nil)
|
|
11
|
+
if dir
|
|
12
|
+
File.read(File.join(dir, file_name))
|
|
13
|
+
else
|
|
14
|
+
File.read(find_in_lookup_paths(file_name))
|
|
15
|
+
end
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
def copy_file(destination, source_file_name, rename: nil)
|
|
17
|
-
source =
|
|
19
|
+
source = find_in_lookup_paths(source_file_name)
|
|
18
20
|
FileUtils.copy(source, File.join(destination, rename || source_file_name))
|
|
19
21
|
end
|
|
20
22
|
|
|
23
|
+
BASE_DIRECTORY = Pathname.new(__dir__).join("templates")
|
|
24
|
+
def self.lookup_paths
|
|
25
|
+
MUTEX.synchronize { @lookup_paths ||= [BASE_DIRECTORY] }
|
|
26
|
+
end
|
|
27
|
+
|
|
21
28
|
private
|
|
22
29
|
|
|
30
|
+
def find_in_lookup_paths(file_name)
|
|
31
|
+
Mimas::Template.lookup_paths.each do |path|
|
|
32
|
+
file_path = path.join(file_name)
|
|
33
|
+
return file_path if File.exist?(file_path)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
raise "Unable to find template: #{file_name}"
|
|
37
|
+
end
|
|
38
|
+
|
|
23
39
|
def read_template(file_name, dir:)
|
|
24
|
-
|
|
40
|
+
if dir
|
|
41
|
+
file = File.read(File.join(dir, "#{file_name}.erb"))
|
|
42
|
+
else
|
|
43
|
+
file = File.read(find_in_lookup_paths("#{file_name}.erb"))
|
|
44
|
+
end
|
|
45
|
+
|
|
25
46
|
ERB.new(file, trim_mode: "-")
|
|
26
47
|
end
|
|
27
48
|
end
|
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
file_server
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
header {
|
|
12
|
+
?strict-transport-security "max-age=31536000; includeSubDomains"
|
|
13
|
+
?x-frame-options "DENY"
|
|
14
|
+
?x-xss-protection "1; mode=block"
|
|
15
|
+
?x-content-type-options "nosniff"
|
|
16
|
+
?referrer-policy "no-referrer-when-downgrade"
|
|
17
|
+
?cache-control "public, max-age=604800, s-maxage=86400"
|
|
18
|
+
}
|
|
19
|
+
|
|
11
20
|
log {
|
|
12
21
|
format console
|
|
13
22
|
output file <%= site_root %>/logs/caddy.log
|
data/lib/mimas/version.rb
CHANGED
data/lib/mimas.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mimas
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ayush Newatia
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-07-
|
|
10
|
+
date: 2026-07-23 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: dry-cli
|
|
@@ -99,12 +99,6 @@ executables:
|
|
|
99
99
|
extensions: []
|
|
100
100
|
extra_rdoc_files: []
|
|
101
101
|
files:
|
|
102
|
-
- ".gitignore"
|
|
103
|
-
- Gemfile
|
|
104
|
-
- Gemfile.lock
|
|
105
|
-
- LICENSE.txt
|
|
106
|
-
- README.md
|
|
107
|
-
- Rakefile
|
|
108
102
|
- bin/mimas
|
|
109
103
|
- lib/mimas.rb
|
|
110
104
|
- lib/mimas/archiver.rb
|
|
@@ -154,10 +148,7 @@ files:
|
|
|
154
148
|
- lib/mimas/terminal/ansi.rb
|
|
155
149
|
- lib/mimas/terminal/printer.rb
|
|
156
150
|
- lib/mimas/version.rb
|
|
157
|
-
|
|
158
|
-
- scripts/release
|
|
159
|
-
- scripts/test
|
|
160
|
-
- tmp/.keep
|
|
151
|
+
homepage: https://codeberg.org/ayushn21/mimas
|
|
161
152
|
licenses:
|
|
162
153
|
- MIT
|
|
163
154
|
metadata: {}
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
mimas (0.1.1)
|
|
5
|
-
bcrypt_pbkdf (~> 1.0)
|
|
6
|
-
dry-cli (~> 1.4)
|
|
7
|
-
ed25519 (~> 1.2)
|
|
8
|
-
logger (~> 1.7)
|
|
9
|
-
net-scp (~> 4.1)
|
|
10
|
-
net-ssh (~> 7.3)
|
|
11
|
-
|
|
12
|
-
GEM
|
|
13
|
-
remote: https://rubygems.org/
|
|
14
|
-
specs:
|
|
15
|
-
ansi (1.6.0)
|
|
16
|
-
bcrypt_pbkdf (1.1.2)
|
|
17
|
-
builder (3.3.0)
|
|
18
|
-
date (3.5.1)
|
|
19
|
-
debug (1.11.1)
|
|
20
|
-
irb (~> 1.10)
|
|
21
|
-
reline (>= 0.3.8)
|
|
22
|
-
drb (2.2.3)
|
|
23
|
-
dry-cli (1.4.1)
|
|
24
|
-
ed25519 (1.4.0)
|
|
25
|
-
erb (6.0.4)
|
|
26
|
-
io-console (0.8.2)
|
|
27
|
-
irb (1.18.0)
|
|
28
|
-
pp (>= 0.6.0)
|
|
29
|
-
prism (>= 1.3.0)
|
|
30
|
-
rdoc (>= 4.0.0)
|
|
31
|
-
reline (>= 0.4.2)
|
|
32
|
-
logger (1.7.0)
|
|
33
|
-
minitest (6.0.6)
|
|
34
|
-
drb (~> 2.0)
|
|
35
|
-
prism (~> 1.5)
|
|
36
|
-
minitest-profile (0.0.2)
|
|
37
|
-
minitest-reporters (1.8.0)
|
|
38
|
-
ansi
|
|
39
|
-
builder
|
|
40
|
-
minitest (>= 5.0, < 7)
|
|
41
|
-
ruby-progressbar
|
|
42
|
-
net-scp (4.1.0)
|
|
43
|
-
net-ssh (>= 2.6.5, < 8.0.0)
|
|
44
|
-
net-ssh (7.3.3)
|
|
45
|
-
pp (0.6.3)
|
|
46
|
-
prettyprint
|
|
47
|
-
prettyprint (0.2.0)
|
|
48
|
-
prism (1.9.0)
|
|
49
|
-
psych (5.4.0)
|
|
50
|
-
date
|
|
51
|
-
stringio
|
|
52
|
-
rake (13.4.2)
|
|
53
|
-
rdoc (7.2.0)
|
|
54
|
-
erb
|
|
55
|
-
psych (>= 4.0.0)
|
|
56
|
-
tsort
|
|
57
|
-
reline (0.6.3)
|
|
58
|
-
io-console (~> 0.5)
|
|
59
|
-
ruby-progressbar (1.13.0)
|
|
60
|
-
stringio (3.2.0)
|
|
61
|
-
tsort (0.2.0)
|
|
62
|
-
|
|
63
|
-
PLATFORMS
|
|
64
|
-
arm64-darwin-23
|
|
65
|
-
ruby
|
|
66
|
-
|
|
67
|
-
DEPENDENCIES
|
|
68
|
-
debug
|
|
69
|
-
mimas!
|
|
70
|
-
minitest
|
|
71
|
-
minitest-profile
|
|
72
|
-
minitest-reporters
|
|
73
|
-
rake
|
|
74
|
-
|
|
75
|
-
CHECKSUMS
|
|
76
|
-
ansi (1.6.0) sha256=ac9ea0c0ea8d32fb4e271348e609963ac78882f34b73836c2a02b3622e666658
|
|
77
|
-
bcrypt_pbkdf (1.1.2) sha256=c2414c23ce66869b3eb9f643d6a3374d8322dfb5078125c82792304c10b94cf6
|
|
78
|
-
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
|
|
79
|
-
date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
|
|
80
|
-
debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6
|
|
81
|
-
drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
|
|
82
|
-
dry-cli (1.4.1) sha256=b8015bb76c708aa8705a36faf694973e75eeeffca39b89c8e172dc6f66a7d874
|
|
83
|
-
ed25519 (1.4.0) sha256=16e97f5198689a154247169f3453ef4cfd3f7a47481fde0ae33206cdfdcac506
|
|
84
|
-
erb (6.0.4) sha256=38e3803694be357fe2bfe312487c74beaf9fb4e5beb3e22498952fe1645b95d9
|
|
85
|
-
io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
|
|
86
|
-
irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
|
|
87
|
-
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
88
|
-
mimas (0.1.1)
|
|
89
|
-
minitest (6.0.6) sha256=153ea36d1d987a62942382b61075745042a2b3123b1cd48f4c3675af9cc7d6f1
|
|
90
|
-
minitest-profile (0.0.2) sha256=caf5306217b59ea2854d75ff6b312e2c139f2948f2b6a39486677b8317b7048e
|
|
91
|
-
minitest-reporters (1.8.0) sha256=8ce5280fb73ad3178ae525454df169b6f28c1b38b1d088ea91815d3a370ba384
|
|
92
|
-
net-scp (4.1.0) sha256=a99b0b92a1e5d360b0de4ffbf2dc0c91531502d3d4f56c28b0139a7c093d1a5d
|
|
93
|
-
net-ssh (7.3.3) sha256=831def58b2c51dcef66ec00d29397d4f210de89c19fe78f95873ca30f386e86a
|
|
94
|
-
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
95
|
-
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
|
96
|
-
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
|
|
97
|
-
psych (5.4.0) sha256=14f72d69a611af663d7d70e4a7b67d9eb1f3ae9f8d916b478961d5a0075ba5b7
|
|
98
|
-
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
|
|
99
|
-
rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192
|
|
100
|
-
reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
|
|
101
|
-
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
102
|
-
stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1
|
|
103
|
-
tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
|
|
104
|
-
|
|
105
|
-
BUNDLED WITH
|
|
106
|
-
4.0.6
|
data/LICENSE.txt
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026-present Ayush Newatia
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
-
a copy of this software and associated documentation files (the
|
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
-
the following conditions:
|
|
12
|
-
|
|
13
|
-
The above copyright notice and this permission notice shall be
|
|
14
|
-
included in all copies or substantial portions of the Software.
|
|
15
|
-
|
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
DELETED
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
# Mimas
|
|
2
|
-
|
|
3
|
-
Mimas is a CLI tool to deploy Ruby apps and static sites to a single server. It provides an opinionated setup to serve sites with [Caddy](https://caddyserver.com) as a reverse proxy.
|
|
4
|
-
|
|
5
|
-
It can provision the server by applying security rules, create the users, configure log rotation, and install required software.
|
|
6
|
-
|
|
7
|
-
Multiple sites can be deployed to the same server. All deploys are zero-downtime. Mimas will create a new `systemd` service for each deploy, healthcheck it, before switching Caddy to the new service, and stopping and removing the old service.
|
|
8
|
-
|
|
9
|
-
It doesn't do anything fancy under the hood, it's all the bash commands and scripts run by Ruby's `Net::SSH` utility.
|
|
10
|
-
|
|
11
|
-
Mimas focuses on deploying apps, and doesn't build the app during deployment. Build your app locally or on your CI server before pushing it using Mimas.
|
|
12
|
-
|
|
13
|
-
It has currently only been tested with Ubuntu 26.04. Mimas is still in early stages of development, so bugs are likely. Use with caution!
|
|
14
|
-
|
|
15
|
-
## Getting Started
|
|
16
|
-
|
|
17
|
-
Install Mimas and create a binstub:
|
|
18
|
-
|
|
19
|
-
```shell
|
|
20
|
-
$ bundle add mimas
|
|
21
|
-
$ bundle binstub mimas
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Run the `init` command to initialise a config file:
|
|
25
|
-
|
|
26
|
-
```shell
|
|
27
|
-
$ bin/mimas init
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
The command will ask you a number of questions about your setup and generate a config file for Mimas, as well as a [Caddyfile](https://caddyserver.com/docs/caddyfile).
|
|
31
|
-
|
|
32
|
-
## Configuration
|
|
33
|
-
|
|
34
|
-
Mimas requires a config file located at `deploy/mimas.rb`. It is defined using a DSL as demonstrated below:
|
|
35
|
-
|
|
36
|
-
```ruby
|
|
37
|
-
# A static site declaration. All shown fields are compulsory.
|
|
38
|
-
# You may pass a name as `site :static do ... end`. When no name
|
|
39
|
-
# is specified, it is set to `:default`.
|
|
40
|
-
site do
|
|
41
|
-
domain "<%= domain %>"
|
|
42
|
-
root_dir "output"
|
|
43
|
-
glob "**/*"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# A Ruby service declaration. For Ruby services, Use the `files` directive rather
|
|
47
|
-
# than `root_dir` and `glob` as shown above. Mimas will create a TAR archive
|
|
48
|
-
# of the array returned by `files` and push that to the server.
|
|
49
|
-
site :app do
|
|
50
|
-
domain "<%= domain %>"
|
|
51
|
-
files do
|
|
52
|
-
`git ls-files -z`.split("\x0")
|
|
53
|
-
.reject { it.match(%r!(bin|mimas.rb|Caddyfile)!) }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Optional path to conduct the healthcheck. Defaults to "/".
|
|
57
|
-
healthcheck_path "/up"
|
|
58
|
-
|
|
59
|
-
# Define the console command for your app here.
|
|
60
|
-
# You can then access the console by running `mimas console SERVER_NAME`
|
|
61
|
-
# console "bundle console"
|
|
62
|
-
|
|
63
|
-
# Assign environment variables for your Ruby process. Return a multi-line string.
|
|
64
|
-
# env do
|
|
65
|
-
# <<~STRING
|
|
66
|
-
# STRING
|
|
67
|
-
# end
|
|
68
|
-
|
|
69
|
-
# Your deploy script. Mimas automatically runs `bundle install` on
|
|
70
|
-
# deploy if no deploy script is defined.
|
|
71
|
-
# Ensure you invoke `bundle install` if you provide your own script here.
|
|
72
|
-
# deploy do
|
|
73
|
-
# <<~STRING
|
|
74
|
-
# STRING
|
|
75
|
-
# end
|
|
76
|
-
|
|
77
|
-
# The services for your Ruby app. Each service will have its own
|
|
78
|
-
# `systemd` file.
|
|
79
|
-
services do
|
|
80
|
-
web do
|
|
81
|
-
start "bundle exec falcon host deploy/falcon.rb"
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# A server declaration. You'll use the server's name as defined here
|
|
87
|
-
# to deploy to it. `host` and `user` are compulsory, but additional
|
|
88
|
-
# parameters for the SSH connection may be defined. They will be passed
|
|
89
|
-
# as-is to `Net::SSH`: https://net-ssh.github.io/ssh/v1/chapter-2.html#s3.
|
|
90
|
-
#
|
|
91
|
-
# `Net::SSH` automatically reads the private key based on your SSH config.
|
|
92
|
-
# More info: https://binarysolo.blog/managing-ssh-key-pairs-for-server-access/
|
|
93
|
-
server :production do
|
|
94
|
-
host "<%= ip %>"
|
|
95
|
-
user "deploy"
|
|
96
|
-
# keys []
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# You can define optionally hooks that run before and after code is pushed
|
|
100
|
-
# to a server. You can use this to build your site locally before deployment.
|
|
101
|
-
# Mimas doesn't build the site on deploy.
|
|
102
|
-
# hooks do
|
|
103
|
-
# before_push do
|
|
104
|
-
# puts "This is a before push hook"
|
|
105
|
-
# end
|
|
106
|
-
|
|
107
|
-
# after_push do
|
|
108
|
-
# puts "This is an after push hook"
|
|
109
|
-
# end
|
|
110
|
-
# end
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
You can define multiple sites in a single project as demonstrated above, you'll just need to `push` them independently. This approach can be useful if you're serving a static site and Ruby service from the same project.
|
|
114
|
-
|
|
115
|
-
### Caddyfile
|
|
116
|
-
|
|
117
|
-
Mimas also requires a Caddyfile specific to your website. It will automatically load it into the main Caddyfile which controls the entire server. `bin/mimas init` will create one for you. It is an ERB template which is processed on each deploy.
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
<%# An example Caddyfile.erb for a Ruby service %>
|
|
121
|
-
<%# In addition to the below variables, the `site` and `server` %>
|
|
122
|
-
<%# objects are also passed to it for additional configuration. %>
|
|
123
|
-
<%# See the source code for usage details on those objects. %>
|
|
124
|
-
|
|
125
|
-
<%= domain %> {
|
|
126
|
-
reverse_proxy {
|
|
127
|
-
to unix/<%= unix_socket %>
|
|
128
|
-
|
|
129
|
-
lb_try_duration 5s
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
log {
|
|
133
|
-
format console
|
|
134
|
-
output file <%= site_root %>/logs/caddy.log
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
If you have multiple sites in your Mimas config, add the site name as an extension to the file name. For example, `Caddyfile.app.erb` will be used for a `site :app do ... end` in the Mimas config file.
|
|
140
|
-
|
|
141
|
-
See the [Caddy docs](https://caddyserver.com/docs/caddyfile-tutorial) for details on the Caddyfile.
|
|
142
|
-
|
|
143
|
-
## Deployment
|
|
144
|
-
|
|
145
|
-
Once you have a valid Mimas config and a Caddyfile, you can provision your server:
|
|
146
|
-
|
|
147
|
-
```shell
|
|
148
|
-
# bin/mimas provision SERVER_NAME
|
|
149
|
-
$ bin/mimas provision production
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
This will harden your server with security rules, install all required software including Ruby and Caddy, and create an `admin` and `deploy` user.
|
|
153
|
-
|
|
154
|
-
Node is not installed as Mimas doesn't build sites during deployment, and is designed specifically to serve Ruby apps.
|
|
155
|
-
|
|
156
|
-
You can then push your website to the server:
|
|
157
|
-
|
|
158
|
-
```shell
|
|
159
|
-
# bin/mimas push SERVER_NAME [SITE_NAME]
|
|
160
|
-
$ bin/mimas push production
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
If nothing goes wrong, and your DNS is configured to point to your server, your site should be live at your domain name!
|
|
164
|
-
|
|
165
|
-
Mimas doesn't currently support rollbacks. Instead, I recommend you revert your code change and deploy again.
|
|
166
|
-
|
|
167
|
-
## Mimas' Server Setup
|
|
168
|
-
|
|
169
|
-
Mimas creates two users on your server: `admin` and `deploy`. Root access and password authentication is disabled. You'll need to use SSH keys to authenticate.
|
|
170
|
-
|
|
171
|
-
The `admin` user has passwordless sudo access, and `deploy` does not. After the server is provisions, neither Mimas nor another automated tool should access the server using the `admin` account. All automated tasks should happen through the `deploy` account.
|
|
172
|
-
|
|
173
|
-
Mimas will install Caddy and set up a root `Caddyfile` in `/home/deploy/http`. This will import the Caddyfiles for all individual sites. The `deploy` user is given specific sudo access to the commands to control the Caddy systemd service.
|
|
174
|
-
|
|
175
|
-
Ruby versions are installed and managed using `ruby-install` and `chruby`. Ruby is built from source so installing a new version of Ruby on your server will take time.
|
|
176
|
-
|
|
177
|
-
Each site is contained in a folder under `/home/deploy/http` named after its domain name. Here's what the file structure looks like:
|
|
178
|
-
|
|
179
|
-
```
|
|
180
|
-
/home/deploy/
|
|
181
|
-
└── http
|
|
182
|
-
└── example.com
|
|
183
|
-
├── Caddyfile
|
|
184
|
-
├── current -> /home/deploy/http/example.com/releases/20260721194912
|
|
185
|
-
├── logs
|
|
186
|
-
├── mimas
|
|
187
|
-
└── releases
|
|
188
|
-
├── 20260721183301
|
|
189
|
-
├── 20260721193851
|
|
190
|
-
└── 20260721194912
|
|
191
|
-
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
On each deploy, a new folder is created under `releases` with the current timestamp. The `current` symlink will always point to the currently live release, and only the last 5 releases are retained. Older releases are deleted on deploy.
|
|
195
|
-
|
|
196
|
-
The `mimas` folder contains a `mimas.env` file which is loaded for each service, and the Unix socket for the Ruby app server.
|
|
197
|
-
|
|
198
|
-
On each deploy, Mimas will create a user systemd service in `~/.config/systemd/user/` and start it. If the healthcheck succeeds, it will point Caddy to the new release and reload it, then stop and delete the old service. This switch should be seamless, without downtime, as long as your application server supports graceful stops without dropping requests (both Puma and Falcon do).
|
|
199
|
-
|
|
200
|
-
## Configuring The App Server
|
|
201
|
-
|
|
202
|
-
Mimas requires your Ruby app to run on a Unix socket. The `MIMAS_UNIX_SOCKET` environment variable defines the path to the socket. Read that into your app server's config and bind it to that path. A new socket is created for each release to avoid clashes so both old and new services can run at the same time.
|
|
203
|
-
|
|
204
|
-
Mimas will create configs for Puma or Falcon when you run `bin/mimas init`. Ensure you read the docs for your server to configure it for production use. The stock configs only contain the settings to bind it to the correct socket, and options like worker and thread count are not set.
|
|
205
|
-
|
|
206
|
-
## How It Works
|
|
207
|
-
|
|
208
|
-
During provisioning, Mimas will install Caddy using the `admin` account and create a systemd service for it which runs under the `deploy` user. The `deploy` user is given specific sudo access only to control this server.
|
|
209
|
-
|
|
210
|
-
A global Caddyfile is created under `/home/deploy/http` which looks like:
|
|
211
|
-
|
|
212
|
-
```
|
|
213
|
-
import caddy.global
|
|
214
|
-
import */Caddyfile
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
`caddy.global` contains settings that apply to all sites. The default configures it to run using HTTP/1.1 and HTTP/2 only. I found HTTP/3 causes weird connection issues in a browser between deploys.
|
|
218
|
-
|
|
219
|
-
The second line automatically imports all site-specific Caddyfiles whenever Caddy is reloaded. This way, you can control your site's config independently.
|
|
220
|
-
|
|
221
|
-
### Static Sites
|
|
222
|
-
|
|
223
|
-
When a static site is deployed, Mimas will create an array of all the output files using the `root_dir` and `glob` directives in the config, and then create a TAR archive of the files. The archive is SCP'd to the server and extracted under a new `releases` folder named after the current timestamp. It will then update the `current` symlink to the latest release.
|
|
224
|
-
|
|
225
|
-
Mimas will not build your site on the server. I believe the app server should not be used as a build server. Use a `before_push` hook to build your site locally or on a CI server.
|
|
226
|
-
|
|
227
|
-
### Ruby Apps
|
|
228
|
-
|
|
229
|
-
To deploy Ruby apps, Mimas will use the the `files` directive in the config to generate an array of files and create a TAR archive. It will then read the `.ruby-version` file, or if one doesn't exist, the `RUBY_VERSION` constant and verify whether that is installed on the server. If it isn't, the deploy will stop there. Install the required version with `bin/mimas install ruby VERSION SERVER_NAME`
|
|
230
|
-
|
|
231
|
-
If the correct Ruby version is installed, deployment will continue as:
|
|
232
|
-
|
|
233
|
-
1. SCP the archive to the server and extract it to a new `releases` folder named after the current timestamp.
|
|
234
|
-
2. Create a new systemd service for the release and start it.
|
|
235
|
-
3. Perform a healthcheck by making a `curl` request to the new release's Unix socket.
|
|
236
|
-
4. Switch the `current` symlink to the new release and reload Caddy.
|
|
237
|
-
5. Gracefully stop the old service and delete it.
|
|
238
|
-
|
|
239
|
-
If deployment fails at any step, all newly released files and services will be cleaned up, and the existing version will continue to be served.
|
|
240
|
-
|
|
241
|
-
## Logs
|
|
242
|
-
|
|
243
|
-
Logs are written to the site's `logs/` folder. For systemd services, the `stdout` and `stderr` streams are both directed to a log file named after the service.
|
|
244
|
-
|
|
245
|
-
Log rotation is automatically configured for this folder.
|
|
246
|
-
|
|
247
|
-
## CLI
|
|
248
|
-
|
|
249
|
-
Run the below command for all CLI options:
|
|
250
|
-
|
|
251
|
-
```shell
|
|
252
|
-
$ bin/mimas help
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
## Incomplete Functionality
|
|
256
|
-
|
|
257
|
-
Mimas creates a `.env` file in the root directory of each site, which is read into the systemd service. There is no built-in way as yet to add content to this file. You'll need to SSH to your server, edit the file, and then re-deploy to pick up the changes. It lives across releases so you won't lose your changes on deploy.
|
|
258
|
-
|
|
259
|
-
You can, however, define environment variables in your Mimas config using `env`. These are written to `<site_root>/mimas/mimas.env`.
|
|
260
|
-
|
|
261
|
-
The purpose of the `.env` file is to store sensitive secrets like API keys that shouldn't be stored in the project. I'm still not completely sure of how to use the file as yet, so it exists but needs manual editing.
|
|
262
|
-
|
|
263
|
-
## Plugins
|
|
264
|
-
|
|
265
|
-
Mimas supports plugins that add or override commands, or add hooks. Common use cases would be to override the `init` command to generate a framework-specific config file, or to add hooks specific to your project or framework.
|
|
266
|
-
|
|
267
|
-
Plugins must advertise that they are Mimas plugins in their gemspec:
|
|
268
|
-
|
|
269
|
-
```ruby
|
|
270
|
-
spec.metadata["mimas_plugin"] = "true"
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
Register your plugin as shown below:
|
|
274
|
-
|
|
275
|
-
```ruby
|
|
276
|
-
Mimas::Plugins.register(Mimas::Plugins::Bridgetown)
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
Here, `Mimas::Plugins::Bridgetown` must be an object (usually a module) that responds to the class methods `hooks` and `commands`
|
|
280
|
-
|
|
281
|
-
The `hooks` method must return a `Mimas::Hooks` object:
|
|
282
|
-
|
|
283
|
-
```ruby
|
|
284
|
-
def hooks
|
|
285
|
-
hooks = Mimas::Hooks.new
|
|
286
|
-
|
|
287
|
-
hooks.before_push do
|
|
288
|
-
`bin/bt deploy`
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
hooks
|
|
292
|
-
end
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
The `commands` method must return a Hash mapping the command name to the class containing it's implementation:
|
|
296
|
-
|
|
297
|
-
```ruby
|
|
298
|
-
def commands
|
|
299
|
-
{ "init" => Commands::Init }
|
|
300
|
-
end
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
The CLI is built on `dry-cli`, so your commands must be structured as per that framework. See [`mimas-bridgetown`](https://codeberg.org/ayushn21/mimas-bridgetown) for a reference implementation.
|
|
304
|
-
|
|
305
|
-
## Design Decisions
|
|
306
|
-
|
|
307
|
-
In this section I'll briefly discuss why I made certain choices for Mimas.
|
|
308
|
-
|
|
309
|
-
### CLI Framework
|
|
310
|
-
|
|
311
|
-
I decided on `dry-cli` as it has an elegant API and allows for easy extensibility. Also, the scope is fairly small so it's easy to follow the source code.
|
|
312
|
-
|
|
313
|
-
### Caddy
|
|
314
|
-
|
|
315
|
-
Anyone who's ever used Nginx knows that hitting your head against the nearest wall is a more productive endeavour than dealing with an Nginx configuration. Caddy has fantastic docs and an easy to read configuration. Anything you could possibly need out of a web server and reverse proxy, Caddy has out of the box.
|
|
316
|
-
|
|
317
|
-
I considered a setup where Falcon was internet-facing and used for SSL termination and SNI resolution to serve one or more apps. It can be started as `falcon virtual` for this very reason. However, Falcon is an app server and not a proxy or web server so it is limiting in what you can do. Also, it would make zero-downtime deploys when upgrading Ruby impossible, as it spawn child processes for each site from the main process.
|
|
318
|
-
|
|
319
|
-
Caddy is the right tool for the job and allows us to manage the proxy independently from the sites and their individual Ruby requirements.
|
|
320
|
-
|
|
321
|
-
### Docker
|
|
322
|
-
|
|
323
|
-
Docker's a bit of a behemoth. It's great when you're deploying to a fleet of servers, but to deploy to a single server, I find it a but excessive. It's also one more tool to understand and learn. Without Docker, there's a few other complexities around managing dependencies, but generally, I feel it's the simpler setup.
|
|
324
|
-
|
|
325
|
-
### The `deploy` User
|
|
326
|
-
|
|
327
|
-
I'm not comfortable with the app or any automated tool having access to an account with `sudo` access. As such I designed the setup so we can do everything we need through the `deploy` user without `sudo` access.
|
|
328
|
-
|
|
329
|
-
## Testing
|
|
330
|
-
|
|
331
|
-
* Run `bundle exec rake test` to run the test suite
|
|
332
|
-
|
|
333
|
-
## Contributing
|
|
334
|
-
|
|
335
|
-
1. Fork it (https://codeberg.org/ayushn21/mimas/fork)
|
|
336
|
-
2. Clone the fork using `git clone` to your local development machine.
|
|
337
|
-
3. Create your feature branch (`git checkout -b my-new-feature`)
|
|
338
|
-
4. Commit your changes (`git commit -am 'Add some feature'`)
|
|
339
|
-
5. Push to the branch (`git push origin my-new-feature`)
|
|
340
|
-
6. Create a new Pull Request
|
|
341
|
-
|
|
342
|
-
## License
|
|
343
|
-
|
|
344
|
-
Mimas is released under the [MIT License](https://opensource.org/licenses/MIT).
|
|
345
|
-
|
|
346
|
-
Copyright © 2026 [Ayush Newatia](https://radioactivetoy.tech)
|
data/Rakefile
DELETED
data/mimas.gemspec
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "lib/mimas/version"
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "mimas"
|
|
7
|
-
spec.version = Mimas::VERSION
|
|
8
|
-
spec.author = "Ayush Newatia"
|
|
9
|
-
spec.email = "ayush@hey.com"
|
|
10
|
-
spec.summary = "Deploy Ruby apps to a single server using an omakase setup"
|
|
11
|
-
spec.license = "MIT"
|
|
12
|
-
|
|
13
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r!^(test)/!) }
|
|
14
|
-
spec.test_files = spec.files.grep(%r!^test/!)
|
|
15
|
-
|
|
16
|
-
spec.executables = ["mimas"]
|
|
17
|
-
spec.bindir = "bin"
|
|
18
|
-
|
|
19
|
-
spec.require_paths = ["lib"]
|
|
20
|
-
|
|
21
|
-
spec.required_ruby_version = ">= 3.4.0"
|
|
22
|
-
|
|
23
|
-
spec.add_dependency "dry-cli", "~> 1.4"
|
|
24
|
-
spec.add_dependency "net-ssh", "~> 7.3"
|
|
25
|
-
spec.add_dependency "net-scp", "~> 4.1"
|
|
26
|
-
spec.add_dependency "ed25519", "~> 1.2"
|
|
27
|
-
spec.add_dependency "bcrypt_pbkdf", "~> 1.0"
|
|
28
|
-
spec.add_dependency "logger", "~> 1.7" # Needed for net-ssh
|
|
29
|
-
end
|
data/scripts/release
DELETED
data/scripts/test
DELETED
data/tmp/.keep
DELETED
|
File without changes
|