vps 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ ---
2
+ description:
3
+ Install software on the server
4
+ usage:
5
+ install HOST [TOOL]
6
+ arguments:
7
+ - host
8
+ - tool
9
+ tasks:
10
+ - task: ensure
11
+ argument: tool
12
+ fallbacks:
13
+ - description: Choose which deploy tool to install
14
+ task: select
15
+ question: Which deployment tool do you want to install?
16
+ options: << playbooks >>
17
+ - task: playbook
18
+ playbook: install/{{ tool }}
@@ -0,0 +1,35 @@
1
+ ---
2
+ source:
3
+ - https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-using-the-repository
4
+ - https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04
5
+ tasks:
6
+ - description: Updating apt package index
7
+ task: remote_execute
8
+ command: sudo apt-get update
9
+ - description: Installing packages which let apt use packages over HTTPS
10
+ task: remote_execute
11
+ command:
12
+ sudo apt-get install
13
+ apt-transport-https
14
+ ca-certificates
15
+ curl
16
+ gnupg-agent
17
+ software-properties-common
18
+ - description: Adding Docker’s official GPG key
19
+ task: remote_execute
20
+ command: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
21
+ - description: Adding the Docker repository to APT sources
22
+ task: remote_execute
23
+ command: sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
24
+ - description: Updating apt package index
25
+ task: remote_execute
26
+ command: sudo apt-get update
27
+ - description: Installing Docker
28
+ task: remote_execute
29
+ command: sudo apt install -y docker-ce docker-compose
30
+ - description: Adding current user to the docker group
31
+ task: remote_execute
32
+ command: sudo usermod -aG docker ${USER}
33
+ - description: Checking docker state
34
+ task: remote_execute
35
+ command: sudo systemctl status docker
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler"
4
+ Bundler.require :default, :development
5
+
6
+ puts "Loading VPS development environment (#{VPS::VERSION})"
7
+ Pry.start
@@ -0,0 +1,69 @@
1
+ <%- upstreams.each do |upstream| %>
2
+
3
+ upstream <%= upstream[:name] %> {
4
+ server <%= upstream[:name] %>:<%= upstream[:port] %>;
5
+ }
6
+ <%- upstream[:domains].partition{|domain| domain.include?("http://")}.reject(&:empty?).each do |domains| %>
7
+ <%-
8
+ https = domains.first.include?("https://")
9
+ domains = domains.collect{|domain| domain.gsub(/https?:\/\//, "")}.join(" ")
10
+ domain = domains.split(" ")[0]
11
+ nginx = upstream[:nginx] || {}
12
+ proxy_pass = "http://#{ upstream[:name] }"
13
+ %>
14
+
15
+ server {
16
+ <%- unless domains.empty? %>
17
+ listen 80;
18
+ server_name <%= domains %>;
19
+ server_tokens off;
20
+
21
+ <%- end %>
22
+ <%- if nginx[:http] %>
23
+ <%= nginx[:http].gsub("PROXY_PASS", proxy_pass).indent(2) %>
24
+
25
+ <%- end %>
26
+ <%- if https %>
27
+ location /.well-known/acme-challenge/ {
28
+ root /var/www/certbot;
29
+ }
30
+
31
+ location / {
32
+ return 301 https://$host$request_uri;
33
+ }
34
+ }
35
+
36
+ server {
37
+ listen 443 ssl;
38
+ server_name <%= domains %>;
39
+ server_tokens off;
40
+
41
+ ssl_certificate /etc/letsencrypt/live/<%= domain %>/fullchain.pem;
42
+ ssl_certificate_key /etc/letsencrypt/live/<%= domain %>/privkey.pem;
43
+ include /etc/letsencrypt/options-ssl-nginx.conf;
44
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
45
+
46
+ <%- end %>
47
+ <%- if nginx[:root] %>
48
+ root <%= nginx[:root] %>;
49
+ <%- end %>
50
+ <%- if nginx[:try_files] %>
51
+ try_files $uri @app;
52
+
53
+ <%- end %>
54
+ <%- if nginx[:https] %>
55
+ <%= nginx[:https].gsub("PROXY_PASS", proxy_pass).indent(2) %>
56
+
57
+ <%- end %>
58
+ location <%= nginx[:try_files] ? "@app" : "/" %> {
59
+ proxy_pass <%= proxy_pass %>;
60
+ proxy_set_header Host $http_host;
61
+ proxy_set_header X-Real-IP $remote_addr;
62
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
63
+ <%- if nginx[:proxy_redirect] %>
64
+ proxy_redirect <%= nginx[:proxy_redirect] %>;
65
+ <%- end %>
66
+ }
67
+ }
68
+ <%- end %>
69
+ <%- end %>
@@ -0,0 +1,58 @@
1
+ version: "3"
2
+ <% https = upstreams.any?{|upstream| upstream[:domains].any?{|domain| domain.include?("https://")}} %>
3
+ services:
4
+
5
+ nginx:
6
+ image: nginx:1.15-alpine
7
+ container_name: nginx
8
+ restart: unless-stopped
9
+ ports:
10
+ - 80:80
11
+ <%- if https %>
12
+ - 443:443
13
+ <%- end %>
14
+ depends_on:
15
+ <%- upstreams.each do |upstream| %>
16
+ - <%= upstream.name %>
17
+ <%- end %>
18
+ volumes:
19
+ - ./data/nginx:/etc/nginx/conf.d
20
+ <%- if https %>
21
+ - ./data/certbot/conf:/etc/letsencrypt
22
+ - ./data/certbot/www:/var/www/certbot
23
+ command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
24
+
25
+ certbot:
26
+ image: certbot/certbot:v0.27.1
27
+ container_name: certbot
28
+ restart: unless-stopped
29
+ volumes:
30
+ - ./data/certbot/conf:/etc/letsencrypt
31
+ - ./data/certbot/www:/var/www/certbot
32
+ entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
33
+ <%- end %>
34
+ <%- services.to_h.each do |name, spec| %>
35
+
36
+ <%= name %>:
37
+ <%= OpenStruct.to_hash(spec).to_yaml.sub(/^.*?\n/, "").indent(4) %>
38
+ <%- end %>
39
+ <%- upstreams.each do |upstream| %>
40
+
41
+ <%= upstream.name %>:
42
+ image: <%= upstream.name %>
43
+ restart: always
44
+ <%- unless upstream[:compose].inspect.match(/\bports\b/) %>
45
+ ports:
46
+ - <%= upstream.port %>
47
+ <%- end %>
48
+ <%- if upstream[:compose] %>
49
+ <%= OpenStruct.to_hash(upstream[:compose]).to_yaml.sub(/^.*?\n/, "").indent(4) %>
50
+ <%- end %>
51
+ <%- end %>
52
+ <%- unless (volumes || []).empty? %>
53
+
54
+ volumes:
55
+ <%- volumes.each do |volume| %>
56
+ <%= volume %>:
57
+ <%- end %>
58
+ <%- end %>
@@ -0,0 +1,13 @@
1
+ FROM elixir:<%= upstream.elixir_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add alpine-sdk \
5
+ && mix local.rebar --force \
6
+ && mix local.hex --force
7
+
8
+ WORKDIR /opt/app
9
+ COPY . .
10
+
11
+ ENV MIX_ENV=prod
12
+ RUN mix do deps.get --only prod, deps.compile
13
+ CMD ["sh", "-c", "mix phx.server"]
@@ -0,0 +1,13 @@
1
+ FROM elixir:<%= upstream.elixir_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add alpine-sdk \
5
+ && mix local.rebar --force \
6
+ && mix local.hex --force
7
+
8
+ WORKDIR /opt/app
9
+ COPY . .
10
+
11
+ ENV MIX_ENV=prod
12
+ RUN mix do deps.get --only prod, deps.compile
13
+ CMD ["sh", "-c", "mix run --no-halt"]
@@ -0,0 +1,16 @@
1
+ FROM ruby:<%= upstream.ruby_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add \
5
+ build-base nodejs tzdata \
6
+ mysql-dev mysql-client --no-install-recommends \
7
+ postgresql-dev postgresql-client \
8
+ libxslt-dev libxml2-dev
9
+
10
+ WORKDIR /opt/app
11
+ COPY . .
12
+
13
+ ENV RACK_ENV=production
14
+ RUN gem install bundler -v <%= upstream.bundler_version %>
15
+ RUN bundle install --without development test
16
+ CMD ["bundle", "exec", "rackup", "config.ru", "-o", "0.0.0.0"]
@@ -0,0 +1,18 @@
1
+ FROM ruby:<%= upstream.ruby_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add \
5
+ build-base nodejs tzdata \
6
+ mysql-dev mysql-client --no-install-recommends \
7
+ postgresql-dev postgresql-client \
8
+ libxslt-dev libxml2-dev
9
+
10
+ WORKDIR /opt/app
11
+ COPY . .
12
+
13
+ ENV RAILS_ENV=production
14
+ EXPOSE <%= upstream.port %>
15
+ RUN gem install bundler -v <%= upstream.bundler_version %>
16
+ RUN bundle install --without development test
17
+ CMD ["rm", "-f", "tmp/pids/server.pid"]
18
+ CMD ["rails", "server", "-b", "0.0.0.0"]
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+
3
+ <%- if (domains = upstream[:domains].collect{|domain| domain.dup.gsub!("https://", "")}.compact).any? %>
4
+ domains=(<%= domains.join(" ") %>)
5
+ email="<%= upstream[:email] || "noreply@#{domains.first}" %>" # Adding a valid address is strongly recommended
6
+ data_path="./data/certbot"
7
+ staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits
8
+ rsa_key_size=4096
9
+
10
+ if [ -d "$data_path" ]; then
11
+ read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
12
+ if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
13
+ exit
14
+ fi
15
+ fi
16
+
17
+ if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
18
+ echo "### Downloading recommended TLS parameters ..."
19
+ mkdir -p "$data_path/conf"
20
+ curl -s https://raw.githubusercontent.com/certbot/certbot/v0.40.1/certbot-nginx/certbot_nginx/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
21
+ curl -s https://raw.githubusercontent.com/certbot/certbot/v0.40.1/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
22
+ echo
23
+ fi
24
+
25
+ echo "### Creating dummy certificate for $domains ..."
26
+ path="/etc/letsencrypt/live/$domains"
27
+ mkdir -p "$data_path/conf/live/$domains"
28
+ docker-compose run --rm --entrypoint "\
29
+ openssl req -x509 -nodes -newkey rsa:1024 -days 1\
30
+ -keyout '$path/privkey.pem' \
31
+ -out '$path/fullchain.pem' \
32
+ -subj '/CN=localhost'" certbot
33
+ echo
34
+
35
+ echo "### Starting nginx ..."
36
+ docker-compose up --force-recreate -d nginx
37
+ echo
38
+
39
+ echo "### Deleting dummy certificate for $domains ..."
40
+ docker-compose run --rm --entrypoint "\
41
+ rm -Rf /etc/letsencrypt/live/$domains && \
42
+ rm -Rf /etc/letsencrypt/archive/$domains && \
43
+ rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
44
+ echo
45
+
46
+ echo "### Requesting Let's Encrypt certificate for $domains ..."
47
+ #Join $domains to -d args
48
+ domain_args=""
49
+ for domain in "${domains[@]}"; do
50
+ domain_args="$domain_args -d $domain"
51
+ done
52
+
53
+ # Select appropriate email arg
54
+ case "$email" in
55
+ "") email_arg="--register-unsafely-without-email" ;;
56
+ *) email_arg="--email $email" ;;
57
+ esac
58
+
59
+ # Enable staging mode if needed
60
+ if [ $staging != "0" ]; then staging_arg="--staging"; fi
61
+
62
+ docker-compose run --rm --entrypoint "\
63
+ certbot certonly --webroot -w /var/www/certbot \
64
+ $staging_arg \
65
+ $email_arg \
66
+ $domain_args \
67
+ --rsa-key-size $rsa_key_size \
68
+ --agree-tos \
69
+ --force-renewal" certbot
70
+ echo
71
+
72
+ echo "### Reloading nginx ..."
73
+ docker-compose exec nginx nginx -s reload
74
+ <%- else %>
75
+ # NO HTTPS
76
+ <%- end %>
@@ -0,0 +1,12 @@
1
+ require_relative "test_helper/coverage"
2
+
3
+ require "minitest"
4
+ require "minitest/autorun"
5
+ require "mocha/setup"
6
+
7
+ def path(path)
8
+ File.expand_path "../../#{path}", __FILE__
9
+ end
10
+
11
+ require "bundler"
12
+ Bundler.require :default, :development, :test
@@ -0,0 +1,8 @@
1
+ if Dir.pwd == File.expand_path("../../..", __FILE__)
2
+ require "simplecov"
3
+ SimpleCov.coverage_dir "test/coverage"
4
+ SimpleCov.start do
5
+ add_group "VPS", "lib"
6
+ add_group "Test suite", "test"
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "../test_helper"
2
+
3
+ module Unit
4
+ class TestVersion < MiniTest::Test
5
+
6
+ describe VPS::VERSION do
7
+ it "has the current version" do
8
+ version = File.read(path("VERSION")).strip
9
+ assert_equal version, VPS::VERSION
10
+ assert File.read(path "CHANGELOG.md").include?("Version #{version} ")
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/vps/version", __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Paul Engel"]
6
+ gem.email = ["pm_engel@icloud.com"]
7
+ gem.summary = %q{Zero-config deployments of Plug, Phoenix, Rack and Rails apps on a clean Ubuntu server using Docker and Let's Encrypt}
8
+ gem.description = %q{Zero-config deployments of Plug, Phoenix, Rack and Rails apps on a clean Ubuntu server using Docker and Let's Encrypt}
9
+ gem.homepage = "https://github.com/archan937/vps"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "vps"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = VPS::VERSION
17
+ gem.licenses = ["MIT"]
18
+
19
+ gem.add_dependency "thor"
20
+ gem.add_dependency "erubis"
21
+ gem.add_dependency "inquirer"
22
+ gem.add_dependency "net-ssh"
23
+ gem.add_dependency "activesupport", ">= 4.1.8"
24
+
25
+ gem.add_development_dependency "pry"
26
+ gem.add_development_dependency "simplecov"
27
+ gem.add_development_dependency "minitest"
28
+ gem.add_development_dependency "mocha"
29
+ end
metadata ADDED
@@ -0,0 +1,214 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vps
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Paul Engel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: erubis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: inquirer
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: net-ssh
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 4.1.8
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 4.1.8
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: minitest
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: mocha
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Zero-config deployments of Plug, Phoenix, Rack and Rails apps on a clean
140
+ Ubuntu server using Docker and Let's Encrypt
141
+ email:
142
+ - pm_engel@icloud.com
143
+ executables:
144
+ - vps
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - ".gitignore"
149
+ - CHANGELOG.md
150
+ - Gemfile
151
+ - MIT-LICENSE
152
+ - README.md
153
+ - Rakefile
154
+ - VERSION
155
+ - bin/vps
156
+ - config/services.yml
157
+ - lib/vps.rb
158
+ - lib/vps/cli.rb
159
+ - lib/vps/cli/domain.rb
160
+ - lib/vps/cli/playbook.rb
161
+ - lib/vps/cli/playbook/state.rb
162
+ - lib/vps/cli/playbook/tasks.rb
163
+ - lib/vps/cli/service.rb
164
+ - lib/vps/cli/upstream.rb
165
+ - lib/vps/core_ext/ostruct.rb
166
+ - lib/vps/core_ext/string.rb
167
+ - lib/vps/version.rb
168
+ - playbooks/deploy.yml
169
+ - playbooks/deploy/docker.yml
170
+ - playbooks/init.yml
171
+ - playbooks/init/ubuntu-18.04.yml
172
+ - playbooks/install.yml
173
+ - playbooks/install/docker/ubuntu-18.04.yml
174
+ - script/console
175
+ - templates/docker/data/nginx/app.conf.erb
176
+ - templates/docker/docker-compose.yml.erb
177
+ - templates/docker/upstream/Dockerfile.phoenix.erb
178
+ - templates/docker/upstream/Dockerfile.plug.erb
179
+ - templates/docker/upstream/Dockerfile.rack.erb
180
+ - templates/docker/upstream/Dockerfile.rails.erb
181
+ - templates/docker/upstream/init-letsencrypt.sh.erb
182
+ - test/test_helper.rb
183
+ - test/test_helper/coverage.rb
184
+ - test/unit/test_version.rb
185
+ - vps.gemspec
186
+ homepage: https://github.com/archan937/vps
187
+ licenses:
188
+ - MIT
189
+ metadata: {}
190
+ post_install_message:
191
+ rdoc_options: []
192
+ require_paths:
193
+ - lib
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ requirements: []
205
+ rubyforge_project:
206
+ rubygems_version: 2.4.5.4
207
+ signing_key:
208
+ specification_version: 4
209
+ summary: Zero-config deployments of Plug, Phoenix, Rack and Rails apps on a clean
210
+ Ubuntu server using Docker and Let's Encrypt
211
+ test_files:
212
+ - test/test_helper.rb
213
+ - test/test_helper/coverage.rb
214
+ - test/unit/test_version.rb