Compare commits
4 Commits
d46907850b
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a3d2d9b33 | |||
| d6ebabce8b | |||
| 5d0f008f6b | |||
| dcbf28a48d |
@@ -117,9 +117,9 @@ uv run ansible-playbook -i inventory.ini playbook.yml
|
|||||||
### 6.1 Refactoring Inline Configurations to Jinja2 Templates
|
### 6.1 Refactoring Inline Configurations to Jinja2 Templates
|
||||||
To improve maintainability and separate configuration data from playbook logic, inline file content blocks in `playbook.yml` were refactored into dedicated Jinja2 template files located in the `templates/` directory:
|
To improve maintainability and separate configuration data from playbook logic, inline file content blocks in `playbook.yml` were refactored into dedicated Jinja2 template files located in the `templates/` directory:
|
||||||
|
|
||||||
* **[templates/Caddyfile.j2](file:///Users/doctor/Git/ovh_gridscale_test_task/templates/Caddyfile.j2)**: Contains Caddy server block definitions and metrics setup.
|
* **[templates/Caddyfile.j2](templates/Caddyfile.j2)**: Contains Caddy server block definitions and metrics setup.
|
||||||
* **[templates/prometheus.yml.j2](file:///Users/doctor/Git/ovh_gridscale_test_task/templates/prometheus.yml.j2)**: Contains global scrape configuration and imports rule files via `rule_files: [/etc/prometheus/alert_rules.yml]`.
|
* **[templates/prometheus.yml.j2](templates/prometheus.yml.j2)**: Contains global scrape configuration and imports rule files via `rule_files: [/etc/prometheus/alert_rules.yml]`.
|
||||||
* **[templates/alert_rules.yml.j2](file:///Users/doctor/Git/ovh_gridscale_test_task/templates/alert_rules.yml.j2)**: Defines Prometheus alert rules for monitoring Caddy service availability and error rates.
|
* **[templates/alert_rules.yml.j2](templates/alert_rules.yml.j2)**: Defines Prometheus alert rules for monitoring Caddy service availability and error rates.
|
||||||
|
|
||||||
The playbook tasks were updated to use `ansible.builtin.template` instead of `ansible.builtin.copy`.
|
The playbook tasks were updated to use `ansible.builtin.template` instead of `ansible.builtin.copy`.
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ resource "null_resource" "ansible_provisioner" {
|
|||||||
]
|
]
|
||||||
|
|
||||||
provisioner "local-exec" {
|
provisioner "local-exec" {
|
||||||
command = "uv run ansible-playbook -i ${local_file.ansible_inventory.filename} playbook.yml"
|
command = "sleep 60 &&uv run ansible-playbook -i ${local_file.ansible_inventory.filename} playbook.yml"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -175,14 +175,14 @@ source .env
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 7.2 Python Environment Initialization & Dependency Setup (`uv`)
|
### 7.2 Python Environment Initialization & Dependency Setup (`uv`)
|
||||||
Initialize Python environment and install Ansible using `uv`:
|
Initialize Python environment and install Ansible along with `passlib` and `bcrypt` (required for Jinja `password_hash` filter) using `uv`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Initialize uv virtual environment and lockfile
|
# Initialize uv virtual environment and lockfile
|
||||||
uv init --bare
|
uv init --bare
|
||||||
|
|
||||||
# Add Ansible dependency
|
# Add Ansible, passlib, and bcrypt dependencies (bcrypt<4.0.0 required for passlib compatibility)
|
||||||
uv add "ansible"
|
uv add ansible passlib "bcrypt<4.0.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.3 Infrastructure Provisioning & Automated Execution
|
### 7.3 Infrastructure Provisioning & Automated Execution
|
||||||
@@ -206,5 +206,135 @@ uv run ansible-playbook -i inventory.ini -l caddy playbook.yml
|
|||||||
uv run ansible-playbook -i inventory.ini -l monitoring playbook.yml
|
uv run ansible-playbook -i inventory.ini -l monitoring playbook.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Additional Task: Nginx Integration and Custom Improvements
|
||||||
|
|
||||||
|
### 8.1 Nginx Infrastructure & Ansible Deployment
|
||||||
|
Expanded the infrastructure to provision a dedicated Nginx web server node (`nginx01`) alongside Caddy and Monitoring nodes:
|
||||||
|
* **Terraform Infrastructure**: Defined `gridscale_storage.storage_nginx` and `gridscale_server.server_nginx` attached to the internal private network (`gridscale_network.network_internal`) with port 80 allowed internally.
|
||||||
|
* **Ansible Automation**: Added an `nginx` play in `playbook.yml` installing Nginx and deploying a custom `index.html.j2` page displaying host metadata.
|
||||||
|
|
||||||
|
### 8.2 HTTPS Reverse Proxying via `sslip.io` Dynamic Subdomains
|
||||||
|
Configured Caddy as the central ingress gateway utilizing `sslip.io` dynamic DNS wildcard resolution to route traffic over HTTPS automatically:
|
||||||
|
* `caddy.<ip>.sslip.io` $\rightarrow$ Caddy default static page
|
||||||
|
* `nginx.<ip>.sslip.io` $\rightarrow$ Reverse proxies to private Nginx IP (`{{ private_ip_nginx }}:80`)
|
||||||
|
* `monitoring.<ip>.sslip.io` $\rightarrow$ Reverse proxies to internal Prometheus IP (`{{ private_ip_monitoring }}:9090`)
|
||||||
|
|
||||||
|
### 8.3 Prometheus Subdomain Security via Basic Authentication & Health Checks
|
||||||
|
Secured access to the Prometheus monitoring interface by embedding Caddy's `basic_auth` directive and active health checking directly into the monitoring subdomain block in `templates/Caddyfile.j2`:
|
||||||
|
|
||||||
|
```caddy
|
||||||
|
monitoring.{{ ansible_default_ipv4.address | replace(".", "-") }}.sslip.io {
|
||||||
|
reverse_proxy {{ private_ip_monitoring }}:9090 {
|
||||||
|
health_uri /-/healthy
|
||||||
|
health_interval 10s
|
||||||
|
health_timeout 5s
|
||||||
|
}
|
||||||
|
basic_auth {
|
||||||
|
{{ demo_user }} {{ demo_pass | password_hash('bcrypt') }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.4 Python Dependencies & `bcrypt` Version Pinning
|
||||||
|
Encountered and resolved a critical dependency issue during Ansible template rendering for `password_hash('bcrypt')`:
|
||||||
|
* **Issue**: `passlib` (1.7.4) failed with `AttributeError: module 'bcrypt' has no attribute '__about__'` when paired with `bcrypt >= 4.0.0`, resulting in a `password cannot be longer than 72 bytes` exception.
|
||||||
|
* **Fix**: Pinned `bcrypt` to `<4.0.0` (`bcrypt==3.2.2`) in `pyproject.toml` and installed via `uv`:
|
||||||
|
```bash
|
||||||
|
uv add ansible passlib "bcrypt<4.0.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.5 Direct Execution Output via Terraform `nonsensitive()`
|
||||||
|
To display all endpoint URLs and auto-generated credentials immediately upon `terraform apply` completion without manual CLI commands:
|
||||||
|
* Wrapped `random_password.demo_pass.result` using Terraform's `nonsensitive()` function in `outputs.tf`:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
output "website_urls" {
|
||||||
|
description = "Website URLs"
|
||||||
|
value = [
|
||||||
|
"Caddy: https://caddy.${replace(gridscale_ipv4.public_ipv4_caddy.ip, ".", "-")}.sslip.io",
|
||||||
|
"Nginx behind Caddy: https://nginx.${replace(gridscale_ipv4.public_ipv4_caddy.ip, ".", "-")}.sslip.io",
|
||||||
|
"Prometheus behind Caddy: https://monitoring.${replace(gridscale_ipv4.public_ipv4_caddy.ip, ".", "-")}.sslip.io",
|
||||||
|
"Login for Monitoring: demo ${nonsensitive(random_password.demo_pass.result)}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.6 Upstream Health Checks & Fault Tolerance in Caddy
|
||||||
|
Configured active health checking inside Caddy's `reverse_proxy` directives in `templates/Caddyfile.j2` to ensure fault tolerance for upstream services:
|
||||||
|
* **Nginx Health Probes**: Periodic `health_uri /` checks every 10 seconds (5s timeout).
|
||||||
|
* **Prometheus Health Probes**: Periodic `health_uri /-/healthy` checks every 10 seconds (5s timeout).
|
||||||
|
* If an upstream service or node becomes unresponsive, Caddy automatically marks the backend as unhealthy and prevents routing traffic to dead backends.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Summary: Service Execution & Access Guide
|
||||||
|
|
||||||
|
### 9.1 Quickstart Execution Steps
|
||||||
|
|
||||||
|
1. **Configure Environment Credentials**:
|
||||||
|
Copy `.env.example` to `.env`, set your Gridscale API credentials, and export them:
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env with your credentials
|
||||||
|
source .env
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Initialize Python Environment & Dependencies**:
|
||||||
|
Initialize `uv` environment and install Ansible, `passlib`, and `bcrypt`:
|
||||||
|
```bash
|
||||||
|
uv init --bare
|
||||||
|
uv add ansible passlib "bcrypt<4.0.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Provision Infrastructure & Execute Playbooks**:
|
||||||
|
Apply Terraform to provision all cloud resources, generate `inventory.ini`, and automatically trigger Ansible configuration management via `null_resource`:
|
||||||
|
```bash
|
||||||
|
terraform init
|
||||||
|
terraform apply -auto-approve
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9.2 Service Access & Endpoints Summary
|
||||||
|
|
||||||
|
Upon successful completion, Terraform outputs all HTTPS endpoints and Basic Authentication credentials:
|
||||||
|
|
||||||
|
| Service | Host / Subdomain Format | Target / Upstream | Access Details |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **Caddy Ingress** | `https://caddy.<caddy-ip-with-dashes>.sslip.io` | Local Caddy static server | Public landing page |
|
||||||
|
| **Nginx Web Server** | `https://nginx.<caddy-ip-with-dashes>.sslip.io` | `http://<nginx-ip-private>:80` | Reverse proxied Hello World page |
|
||||||
|
| **Prometheus Monitoring** | `https://monitoring.<caddy-ip-with-dashes>.sslip.io` | `http://<monitoring-ip-private>:9090` with caddy `basic_auth` | **Username**: `demo`<br>**Password**: Auto-generated password from Terraform output |
|
||||||
|
|
||||||
|
*(Optional)* Display all endpoint URLs and active credentials at any time:
|
||||||
|
```bash
|
||||||
|
terraform output website_urls
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Exercise Requirement Traceability & Execution Summary
|
||||||
|
|
||||||
|
The following matrix maps every requirement, deliverable, and bonus task from the Gridscale hiring exercise prompt to its exact technical implementation, file location, and execution method in this repository:
|
||||||
|
|
||||||
|
| Exercise Requirement / Task | Status | Implementation Details & File Location | Execution & Automation Method |
|
||||||
|
| :--- | :---: | :--- | :--- |
|
||||||
|
| **Install & Configure Caddy Server** | Completed | Provisioned `caddy01` VM on Debian 13 in [resources.tf](resources.tf). Installed Caddy via Deb822 repo in [playbook.yml](playbook.yml#L41-L80). | Automated via Ansible `ansible.builtin.apt` & `ansible.builtin.template` |
|
||||||
|
| **Serve Sample Web Application** | Completed | Configured static file server (`root * /usr/share/caddy`, `file_server`) in [templates/Caddyfile.j2](templates/Caddyfile.j2#L10-L13). | Rendered via Ansible template `Caddyfile.j2` |
|
||||||
|
| **Prometheus Monitoring Setup** | Completed | Provisioned `monitoring01` VM in [resources.tf](resources.tf). Installed Prometheus in [playbook.yml](playbook.yml#L81-L120). | Configured scrape job `caddy` targeting `{{ private_ip_caddy }}:2019` |
|
||||||
|
| **Metrics Collection (Codes, Latency, Uptime)** | Completed | Enabled Caddy metrics directive `metrics /metrics` with `per_host` and `observe_catchall_hosts` on Admin API `:2019` in [templates/Caddyfile.j2](templates/Caddyfile.j2#L1-L9). | Scraped every 15s by Prometheus over internal network (`192.168.121.0/27`) |
|
||||||
|
| **Prometheus Alerting Pipeline & Rules** | Completed | Defined `Caddy Down` (`up{job="caddy"} == 0`) and `CaddyHighHTTP4xxErrorRateService` (> 5% 4xx rate) rules in [templates/alert_rules.yml.j2](templates/alert_rules.yml.j2). Imported in [templates/prometheus.yml.j2](templates/prometheus.yml.j2). | Deployed to `/etc/prometheus/alert_rules.yml` via Ansible |
|
||||||
|
| **IaC Automation (Terraform + Ansible)** | Completed | 100% automated with Terraform (Gridscale provider) & Ansible. Built `null_resource.ansible_provisioner` in [inventory.tf](inventory.tf#L29-L43) to execute Ansible automatically. | Runs end-to-end via `terraform apply -auto-approve` |
|
||||||
|
| **Additional Task: Nginx "Hello World" VM** | Completed | Provisioned `nginx01` VM in [resources.tf](resources.tf). Installed Nginx and deployed `index.html.j2` in [playbook.yml](playbook.yml#L121-L140). | Bound strictly to internal private IP (`192.168.121.5:80`) |
|
||||||
|
| **Additional Task: Caddy Reverse Proxy & Routing** | Completed | Configured subdomain reverse proxy routing in [templates/Caddyfile.j2](templates/Caddyfile.j2#L15-L31): `nginx.<ip>.sslip.io` $\rightarrow$ Nginx, `monitoring.<ip>.sslip.io` $\rightarrow$ Prometheus. | Managed via Caddy ingress rules |
|
||||||
|
| **Bonus: Upstream Health Checks & Fault Tolerance** | Completed | Added `health_uri /` (Nginx) and `health_uri /-/healthy` (Prometheus) with 10s intervals in [templates/Caddyfile.j2](templates/Caddyfile.j2#L16-L28). | Probed actively by Caddy to bypass dead nodes |
|
||||||
|
| **Bonus: SSL Termination & Client Encryption** | Completed | Used `sslip.io` dynamic wildcard subdomains on port 443 in [templates/Caddyfile.j2](templates/Caddyfile.j2). | Caddy Auto-HTTPS manages Let's Encrypt TLS termination |
|
||||||
|
| **Deliverables: Endpoints & Output Credentials** | Completed | Configured unmasked output using `nonsensitive()` in [outputs.tf](outputs.tf). | Printed directly to terminal on `terraform apply` |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+14
-2
@@ -1,3 +1,8 @@
|
|||||||
|
resource "random_password" "demo_pass" {
|
||||||
|
length = 16
|
||||||
|
special = true
|
||||||
|
}
|
||||||
|
|
||||||
resource "local_file" "ansible_inventory" {
|
resource "local_file" "ansible_inventory" {
|
||||||
filename = "${path.module}/inventory.ini"
|
filename = "${path.module}/inventory.ini"
|
||||||
file_permission = "0644"
|
file_permission = "0644"
|
||||||
@@ -6,12 +11,18 @@ resource "local_file" "ansible_inventory" {
|
|||||||
ansible_ssh_extra_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
ansible_ssh_extra_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
||||||
private_ip_caddy='${gridscale_server.server_caddy.network[1].auto_assigned_ip}'
|
private_ip_caddy='${gridscale_server.server_caddy.network[1].auto_assigned_ip}'
|
||||||
private_ip_monitoring='${gridscale_server.server_monitoring.network[1].auto_assigned_ip}'
|
private_ip_monitoring='${gridscale_server.server_monitoring.network[1].auto_assigned_ip}'
|
||||||
|
private_ip_nginx='${gridscale_server.server_nginx.network[1].auto_assigned_ip}'
|
||||||
|
demo_pass="${random_password.demo_pass.result}"
|
||||||
|
demo_user="demo"
|
||||||
|
|
||||||
[caddy]
|
[caddy]
|
||||||
${var.caddy_hostname} ansible_host=${gridscale_ipv4.public_ipv4.ip} ansible_user=root
|
${var.caddy_hostname} ansible_host=${gridscale_ipv4.public_ipv4_caddy.ip} ansible_user=root
|
||||||
|
|
||||||
[monitoring]
|
[monitoring]
|
||||||
${var.monitoring_hostname} ansible_host=${gridscale_ipv4.public_ipv4_monitoring.ip} ansible_user=root
|
${var.monitoring_hostname} ansible_host=${gridscale_ipv4.public_ipv4_monitoring.ip} ansible_user=root
|
||||||
|
|
||||||
|
[nginx]
|
||||||
|
${var.nginx_hostname} ansible_host=${gridscale_ipv4.public_ipv4_nginx.ip} ansible_user=root
|
||||||
EOT
|
EOT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,7 +30,8 @@ resource "null_resource" "ansible_provisioner" {
|
|||||||
depends_on = [
|
depends_on = [
|
||||||
local_file.ansible_inventory,
|
local_file.ansible_inventory,
|
||||||
gridscale_server.server_caddy,
|
gridscale_server.server_caddy,
|
||||||
gridscale_server.server_monitoring
|
gridscale_server.server_monitoring,
|
||||||
|
gridscale_server.server_nginx
|
||||||
]
|
]
|
||||||
|
|
||||||
provisioner "local-exec" {
|
provisioner "local-exec" {
|
||||||
|
|||||||
+20
-4
@@ -1,6 +1,6 @@
|
|||||||
output "caddy_public_ip" {
|
output "caddy_public_ip" {
|
||||||
description = "Public IPv4 address of the Caddy server"
|
description = "Public IPv4 address of the Caddy server"
|
||||||
value = gridscale_ipv4.public_ipv4.ip
|
value = gridscale_ipv4.public_ipv4_caddy.ip
|
||||||
}
|
}
|
||||||
|
|
||||||
output "monitoring_public_ip" {
|
output "monitoring_public_ip" {
|
||||||
@@ -8,6 +8,11 @@ output "monitoring_public_ip" {
|
|||||||
value = gridscale_ipv4.public_ipv4_monitoring.ip
|
value = gridscale_ipv4.public_ipv4_monitoring.ip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output "nginx_public_ip" {
|
||||||
|
description = "Public IPv4 address of the Nginx server"
|
||||||
|
value = gridscale_ipv4.public_ipv4_nginx.ip
|
||||||
|
}
|
||||||
|
|
||||||
output "caddy_private_ip" {
|
output "caddy_private_ip" {
|
||||||
description = "Private IPv4 address of the Caddy server"
|
description = "Private IPv4 address of the Caddy server"
|
||||||
value = gridscale_server.server_caddy.network[1].auto_assigned_ip
|
value = gridscale_server.server_caddy.network[1].auto_assigned_ip
|
||||||
@@ -18,7 +23,18 @@ output "monitoring_private_ip" {
|
|||||||
value = gridscale_server.server_monitoring.network[1].auto_assigned_ip
|
value = gridscale_server.server_monitoring.network[1].auto_assigned_ip
|
||||||
}
|
}
|
||||||
|
|
||||||
output "ansible_inventory" {
|
output "nginx_private_ip" {
|
||||||
description = "Generated Ansible inventory content"
|
description = "Private IPv4 address of the Nginx server"
|
||||||
value = local_file.ansible_inventory.content
|
value = gridscale_server.server_nginx.network[1].auto_assigned_ip
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
output "website_urls" {
|
||||||
|
description = "Website URLs"
|
||||||
|
value = [
|
||||||
|
"Caddy: https://caddy.${replace(gridscale_ipv4.public_ipv4_caddy.ip, ".", "-")}.sslip.io",
|
||||||
|
"Nginx behind Caddy: https://nginx.${replace(gridscale_ipv4.public_ipv4_caddy.ip, ".", "-")}.sslip.io",
|
||||||
|
"Prometheus behind Caddy: https://monitoring.${replace(gridscale_ipv4.public_ipv4_caddy.ip, ".", "-")}.sslip.io",
|
||||||
|
"Login for Monitoring: demo ${nonsensitive(random_password.demo_pass.result)}"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -115,3 +115,22 @@
|
|||||||
src: prometheus.yml.j2
|
src: prometheus.yml.j2
|
||||||
dest: /etc/prometheus/prometheus.yml
|
dest: /etc/prometheus/prometheus.yml
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Configure Nginx Server
|
||||||
|
hosts: nginx
|
||||||
|
become: true
|
||||||
|
tags:
|
||||||
|
- nginx
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Install Nginx
|
||||||
|
ansible.builtin.apt:
|
||||||
|
pkg:
|
||||||
|
- nginx
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create Hello World page
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: index.html.j2
|
||||||
|
dest: /var/www/html/index.html
|
||||||
|
mode: "0644"
|
||||||
|
|||||||
+84
-20
@@ -7,12 +7,12 @@ resource "gridscale_network" "network_internal"{
|
|||||||
dhcp_reserved_subnet = ["192.168.121.0/31"]
|
dhcp_reserved_subnet = ["192.168.121.0/31"]
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "gridscale_ipv4" "public_ipv4" {
|
resource "gridscale_ipv4" "public_ipv4_caddy" {
|
||||||
name = "public_ipv4"
|
name = "public_ipv4_caddy"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "gridscale_ipv6" "public_ipv6" {
|
resource "gridscale_ipv6" "public_ipv6_caddy" {
|
||||||
name = "public_ipv6"
|
name = "public_ipv6_caddy"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "gridscale_ipv4" "public_ipv4_monitoring" {
|
resource "gridscale_ipv4" "public_ipv4_monitoring" {
|
||||||
@@ -23,6 +23,14 @@ resource "gridscale_ipv6" "public_ipv6_monitoring" {
|
|||||||
name = "public_ipv6_monitoring"
|
name = "public_ipv6_monitoring"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource "gridscale_ipv4" "public_ipv4_nginx" {
|
||||||
|
name = "public_ipv4_nginx"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "gridscale_ipv6" "public_ipv6_nginx" {
|
||||||
|
name = "public_ipv6_nginx"
|
||||||
|
}
|
||||||
|
|
||||||
data "gridscale_template" "template_debian_13" {
|
data "gridscale_template" "template_debian_13" {
|
||||||
name = "Debian 13"
|
name = "Debian 13"
|
||||||
}
|
}
|
||||||
@@ -68,6 +76,13 @@ resource "gridscale_server" "server_caddy" {
|
|||||||
dst_port = 80
|
dst_port = 80
|
||||||
comment = "Allow HTTP access"
|
comment = "Allow HTTP access"
|
||||||
}
|
}
|
||||||
|
rules_v4_in {
|
||||||
|
order = 15
|
||||||
|
protocol = "tcp"
|
||||||
|
action = "accept"
|
||||||
|
dst_port = 443
|
||||||
|
comment = "Allow HTTPS access"
|
||||||
|
}
|
||||||
rules_v6_in {
|
rules_v6_in {
|
||||||
order = 0
|
order = 0
|
||||||
protocol = "tcp"
|
protocol = "tcp"
|
||||||
@@ -82,6 +97,13 @@ resource "gridscale_server" "server_caddy" {
|
|||||||
dst_port = 80
|
dst_port = 80
|
||||||
comment = "Allow HTTPv6 access"
|
comment = "Allow HTTPv6 access"
|
||||||
}
|
}
|
||||||
|
rules_v6_in {
|
||||||
|
order = 15
|
||||||
|
protocol = "tcp"
|
||||||
|
action = "accept"
|
||||||
|
dst_port = 443
|
||||||
|
comment = "Allow HTTPSv6 access"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
network {
|
network {
|
||||||
# Private network
|
# Private network
|
||||||
@@ -95,8 +117,8 @@ resource "gridscale_server" "server_caddy" {
|
|||||||
src_cidr = "192.168.121.0/27"
|
src_cidr = "192.168.121.0/27"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ipv4 = gridscale_ipv4.public_ipv4.id
|
ipv4 = gridscale_ipv4.public_ipv4_caddy.id
|
||||||
ipv6 = gridscale_ipv6.public_ipv6.id
|
ipv6 = gridscale_ipv6.public_ipv6_caddy.id
|
||||||
timeouts {
|
timeouts {
|
||||||
create = "10m"
|
create = "10m"
|
||||||
}
|
}
|
||||||
@@ -131,13 +153,6 @@ resource "gridscale_server" "server_monitoring" {
|
|||||||
dst_port = 22
|
dst_port = 22
|
||||||
comment = "Allow SSH access"
|
comment = "Allow SSH access"
|
||||||
}
|
}
|
||||||
rules_v4_in {
|
|
||||||
order = 10
|
|
||||||
protocol = "tcp"
|
|
||||||
action = "accept"
|
|
||||||
dst_port = 80
|
|
||||||
comment = "Allow HTTP access"
|
|
||||||
}
|
|
||||||
rules_v6_in {
|
rules_v6_in {
|
||||||
order = 0
|
order = 0
|
||||||
protocol = "tcp"
|
protocol = "tcp"
|
||||||
@@ -145,13 +160,6 @@ resource "gridscale_server" "server_monitoring" {
|
|||||||
dst_port = 22
|
dst_port = 22
|
||||||
comment = "Allow SSHv6 access"
|
comment = "Allow SSHv6 access"
|
||||||
}
|
}
|
||||||
rules_v6_in {
|
|
||||||
order = 10
|
|
||||||
protocol = "tcp"
|
|
||||||
action = "accept"
|
|
||||||
dst_port = 80
|
|
||||||
comment = "Allow HTTPv6 access"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
network {
|
network {
|
||||||
# Private Network
|
# Private Network
|
||||||
@@ -163,3 +171,59 @@ resource "gridscale_server" "server_monitoring" {
|
|||||||
create = "10m"
|
create = "10m"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resource "gridscale_storage" "storage_nginx" {
|
||||||
|
name = "storage_nginx"
|
||||||
|
storage_type = "storage"
|
||||||
|
capacity = 20
|
||||||
|
template {
|
||||||
|
sshkeys = [gridscale_sshkey.sshkey_richard.id]
|
||||||
|
template_uuid = data.gridscale_template.template_debian_13.id
|
||||||
|
hostname = var.nginx_hostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "gridscale_server" "server_nginx" {
|
||||||
|
name = var.nginx_hostname
|
||||||
|
cores = 2
|
||||||
|
memory = 1
|
||||||
|
power = true
|
||||||
|
storage {
|
||||||
|
object_uuid = gridscale_storage.storage_nginx.id
|
||||||
|
}
|
||||||
|
network {
|
||||||
|
# Public Network
|
||||||
|
object_uuid = "5557a73b-31ee-4b1f-aa15-7789ad6ae04c"
|
||||||
|
rules_v4_in {
|
||||||
|
order = 0
|
||||||
|
protocol = "tcp"
|
||||||
|
action = "accept"
|
||||||
|
dst_port = 22
|
||||||
|
comment = "Allow SSH access"
|
||||||
|
}
|
||||||
|
rules_v6_in {
|
||||||
|
order = 0
|
||||||
|
protocol = "tcp"
|
||||||
|
action = "accept"
|
||||||
|
dst_port = 22
|
||||||
|
comment = "Allow SSHv6 access"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
network {
|
||||||
|
# Private Network
|
||||||
|
object_uuid = gridscale_network.network_internal.id
|
||||||
|
rules_v4_in {
|
||||||
|
order = 10
|
||||||
|
protocol = "tcp"
|
||||||
|
action = "accept"
|
||||||
|
dst_port = 80
|
||||||
|
comment = "Allow HTTP access for Loadbalancer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipv4 = gridscale_ipv4.public_ipv4_nginx.id
|
||||||
|
ipv6 = gridscale_ipv6.public_ipv6_nginx.id
|
||||||
|
timeouts {
|
||||||
|
create = "10m"
|
||||||
|
}
|
||||||
|
}
|
||||||
+20
-1
@@ -7,7 +7,26 @@
|
|||||||
origins http://{{ private_ip_caddy }}:2019
|
origins http://{{ private_ip_caddy }}:2019
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:80 {
|
caddy.{{ ansible_default_ipv4.address | replace(".", "-") }}.sslip.io {
|
||||||
root * /usr/share/caddy
|
root * /usr/share/caddy
|
||||||
file_server
|
file_server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nginx.{{ ansible_default_ipv4.address | replace(".", "-") }}.sslip.io {
|
||||||
|
reverse_proxy {{ private_ip_nginx }}:80 {
|
||||||
|
health_uri /
|
||||||
|
health_interval 10s
|
||||||
|
health_timeout 5s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
monitoring.{{ ansible_default_ipv4.address | replace(".", "-") }}.sslip.io {
|
||||||
|
reverse_proxy {{ private_ip_monitoring }}:9090 {
|
||||||
|
health_uri /-/healthy
|
||||||
|
health_interval 10s
|
||||||
|
health_timeout 5s
|
||||||
|
}
|
||||||
|
basic_auth {
|
||||||
|
{{ demo_user }} {{ demo_pass | password_hash('bcrypt') }}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Hello World</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
<p>This is {{ ansible_hostname }}</p>
|
||||||
|
<p>Listening on {{ private_ip_nginx }}</p>
|
||||||
|
<p>Behind Reverseproxy from Caddy</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -20,3 +20,9 @@ variable "monitoring_hostname" {
|
|||||||
description = "Monitoring hostname"
|
description = "Monitoring hostname"
|
||||||
default = "monitoring01"
|
default = "monitoring01"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "nginx_hostname" {
|
||||||
|
type = string
|
||||||
|
description = "Nginx hostname"
|
||||||
|
default = "nginx01"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user