Compare commits

...

48 Commits

Author SHA1 Message Date
Nemo bd95967113 upgrade miniflux and gitea 2023-11-28 10:35:39 +05:30
Nemo 3f3f0fd55c re-enable GPU on Emby 2023-10-26 13:10:47 +05:30
Nemo 1b1bbcabbc drop act-exporter
I archived the repo, and no longer maintain it. ACT changed
their portal too much for this to keep working. Further,
the ACT app/portal now provide detailed stats on internet
usage, so this is not that helpful any more.
2023-10-26 13:09:32 +05:30
Nemo dfd0f94662 fix resource limits for grafana,cadvisor 2023-10-26 13:08:14 +05:30
Nemo 09c1094fc5 upgrade mastodon 2023-10-26 13:07:56 +05:30
Nemo 29368acfed upgrade miniflux 2023-10-26 13:07:45 +05:30
Nemo e18d8b11b1 Adds home-assistant
Trying to run https://hackaday.com/2021/07/24/esp8266-adds-wifi-logging-to-ikeas-air-quality-sensor/
2023-08-03 17:00:18 +05:30
Nemo 1feaf2e4f6 Migrate Emby to the SSD, and configure backups
Note that creating the directory alone doesn't do much.
You still have to configure backups and schedule them in the UI.
2023-07-27 13:36:00 +05:30
Nemo 2c52cd0cb7 gitea/miniflux upgrades 2023-07-26 09:40:02 +05:30
Nemo b83dd37365 [radicale] switch to ssd 2023-07-10 19:59:55 +05:30
Nemo af2be53caa [navidrome] Move to ssd 2023-07-10 17:12:03 +05:30
Nemo 9e8c5710f2 upgrade mastodon and use persistent redis 2023-07-10 17:01:50 +05:30
Nemo e4858d5d05 move sonarr/radarr to ssd 2023-07-10 17:01:30 +05:30
Nemo d59512c625 HSTS Preload on tatooine.club 2023-06-22 14:24:26 +05:30
Nemo 4a4504447f upgrade miniflux 2023-06-22 13:15:17 +05:30
Nemo 9b316b036b upgrade mastodon 2023-06-22 13:15:10 +05:30
Nemo f9b52957a8 fix resolver for dns/acme 2023-06-01 14:01:12 +05:30
Nemo 9b79cab3af gitea upgrade and fixes
fixes the svg favicons, but these are not nice
2023-06-01 14:01:06 +05:30
Nemo 5bd44d411f mastodon image conflict fixes 2023-06-01 14:00:08 +05:30
Nemo 406f4557fe fix+upgrade miniflux resource limits 2023-06-01 13:59:55 +05:30
Nemo 938ed017c9 Upgrade mastodon 2023-03-11 17:19:01 +05:30
Nemo 4f2a5b2cb4 Additional Mastodon secrets 2022-12-26 13:19:00 +05:30
Nemo ecaacaf3a5 [transmission] Upgrade configuration 2022-12-26 12:51:44 +05:30
Nemo af20a4efb9 [traefik] Upgrade 1.17 conf for tatooine.club 2022-12-26 12:51:30 +05:30
Nemo 18f32691f6 [media] Upgrade subnet size 2022-12-26 12:50:54 +05:30
Nemo eb1c40df6e [kaarana] Unused, but upgraded 2022-12-26 12:50:43 +05:30
Nemo 4b6b07c09a [db] Increase connections for mastodon 2022-12-26 12:50:31 +05:30
Nemo 48b93bf25d GPU and provider upgrades.
Applied to jupyter container
2022-12-26 12:49:52 +05:30
Nemo 8a894175a9 [miniflux] Upgrade to 2.0.39 2022-12-26 12:49:23 +05:30
Nemo 30fd75ae52 [main] Mastodon added 2022-12-26 12:49:13 +05:30
Nemo 9f6048a971 [gitea] Upgrades to 1.17 2022-12-26 12:48:59 +05:30
Nemo 442ec2d5d3 [traefik] New tatooine.club keys
Had to disable redirect
2022-12-26 12:48:34 +05:30
Nemo 9f04ebe4c4 [rss-bridge] Switch to upstream
Most of my changes are merged: captnemo.in/rss/
So I can switch to tracking upstream instead
2022-12-26 12:48:03 +05:30
Nemo 587b6258bb Mastodon: Initial Configuration
This is missing some secrets, will commit those later
2022-12-26 12:47:48 +05:30
Nemo da4fc888ef [WIP] Traefik v2 migration 2022-12-26 12:46:31 +05:30
Nemo 10ba57590b Switch from latest -> image_id
former is deprecated
2022-12-26 12:46:09 +05:30
Nemo 8a0ead5bb0 [postgres] Increase memory for mastodon 2022-12-26 12:44:55 +05:30
Nemo 36996a0ace Increase network size for pg to add mastodon containers 2022-12-26 12:44:03 +05:30
Nemo 24079f41a2 Upgrade Terraform version 2022-12-26 12:43:47 +05:30
Nemo 51dd19cdc8 add prowlarr 2022-02-02 19:06:13 +05:30
Nemo 1235775ed0 upgrade gitea to 1.16 2022-02-02 19:03:28 +05:30
Nemo ffa2517903 addded kavita then removed it 2022-01-08 22:19:47 +05:30
Nemo ba763d585c minor fixes and upgrades 2022-01-08 22:19:38 +05:30
Nemo f6b1954e8f no more firefox sync, Mozilla makes this too hard 2021-10-16 11:41:30 +05:30
Nemo 137eb3469f
Terraform Upgrade to 1.x (#3)
Co-authored-by: Hashfyre <joy.bhattacherjee@gmail.com>
2021-10-15 12:54:13 +00:00
Nemo 8d7875d174 Fix radicale 2021-04-14 12:30:35 +05:30
Nemo 9273447567 increase memory for radicale 2021-04-14 12:08:31 +05:30
Nemo eae805e596 Update gitea, improve config 2021-04-14 12:08:21 +05:30
129 changed files with 1852 additions and 1178 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
.terraform .terraform
*.tfstate *.tfstate
*.tfstate.backup *.tfstate.backup
*.terraform.lock.hcl
*.out *.out
*.backup *.backup
secrets secrets

View File

@ -1 +1 @@
0.11.13 1.3.6

18
HACKING.md Normal file
View File

@ -0,0 +1,18 @@
# Hacking on the thing
Generate certs as per:
https://gist.github.com/captn3m0/2c2e723b2dcd5cdaad733aad12be59a2
Copy ca.pem, server-cert.pem, server-key.pem to /etc/docker/certs.
Make sure server-key.pem is 0400 in permissions.
Run `systemctl edit docker`
````
/etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=/etc/docker/certs/ca.pem --tlscert=/etc/docker/certs/server-cert.pem --tlskey=/etc/docker/certs/server-key.pem -H=0.0.0.0:2376 -H unix:///var/run/docker.sock
````

View File

@ -42,7 +42,6 @@ Currently running the following (all links are to the `store.docker.com` links f
| image | tag | module/link | | image | tag | module/link |
| -------------------------------- | ---------- | ---------------------------------------------------- | | -------------------------------- | ---------- | ---------------------------------------------------- |
| captn3m0/opml-gen | latest | https://opml.bb8.fun | | captn3m0/opml-gen | latest | https://opml.bb8.fun |
| captn3m0/prometheus-act-exporter | latest | https://git.captnemo.in/nemo/prometheus-act-exporter |
| captn3m0/rss-bridge | latest | https://github.com/RSS-Bridge/rss-bridge | | captn3m0/rss-bridge | latest | https://github.com/RSS-Bridge/rss-bridge |
| captn3m0/speedtest-exporter | alpine | https://github.com/stefanwalther/speedtest-exporter | | captn3m0/speedtest-exporter | alpine | https://github.com/stefanwalther/speedtest-exporter |
| emby/embyserver | latest | https://emby.media | | emby/embyserver | latest | https://emby.media |

View File

@ -4,18 +4,18 @@
*/ */
resource "cloudflare_record" "home" { resource "cloudflare_record" "home" {
domain = "${var.domain}" zone_id = var.zone_id
name = "in" name = "in"
value = "${var.ips["eth0"]}" value = var.ips["eth0"]
type = "A" type = "A"
} }
resource "cloudflare_record" "home-wildcard" { resource "cloudflare_record" "home-wildcard" {
domain = "${var.domain}" zone_id = var.zone_id
name = "*.in" name = "*.in"
value = "${cloudflare_record.home.hostname}" value = cloudflare_record.home.hostname
type = "CNAME" type = "CNAME"
ttl = 3600 ttl = 3600
} }
/** /**
@ -23,42 +23,42 @@ resource "cloudflare_record" "home-wildcard" {
* *.bb8.fun -> bb8.fun * *.bb8.fun -> bb8.fun
*/ */
resource "cloudflare_record" "internet" { resource "cloudflare_record" "internet" {
domain = "${var.domain}" zone_id = var.zone_id
name = "@" name = "@"
value = "${var.droplet_ip}" value = var.droplet_ip
type = "A" type = "A"
} }
resource "cloudflare_record" "internet-wildcard" { resource "cloudflare_record" "internet-wildcard" {
domain = "${var.domain}" zone_id = var.zone_id
name = "*.${var.domain}" name = var.domain
value = "${cloudflare_record.internet.hostname}" value = cloudflare_record.internet.hostname
type = "CNAME" type = "CNAME"
ttl = 3600 ttl = 3600
} }
resource "cloudflare_record" "dns" { resource "cloudflare_record" "dns" {
domain = "${var.domain}" zone_id = var.zone_id
name = "dns" name = "dns"
value = "${var.ips["static"]}" value = var.ips["static"]
type = "A" type = "A"
} }
resource "cloudflare_record" "doh" { resource "cloudflare_record" "doh" {
domain = "${var.domain}" zone_id = var.zone_id
name = "doh" name = "doh"
value = "${var.ips["static"]}" value = var.ips["static"]
type = "A" type = "A"
} }
// This ensures that _acme-challenge is not a CNAME // This ensures that _acme-challenge is not a CNAME
// alongside the above wildcard CNAME entry. // alongside the above wildcard CNAME entry.
resource "cloudflare_record" "acme-no-cname-1" { resource "cloudflare_record" "acme-no-cname-1" {
domain = "${var.domain}" zone_id = var.zone_id
name = "_acme-challenge.${var.domain}" name = "_acme-challenge.${var.domain}"
type = "A" type = "A"
value = "127.0.0.1" value = "127.0.0.1"
ttl = "300" ttl = "300"
} }
/** /**
@ -66,18 +66,18 @@ resource "cloudflare_record" "acme-no-cname-1" {
* *.vpn.bb8.fun * *.vpn.bb8.fun
*/ */
resource "cloudflare_record" "vpn" { resource "cloudflare_record" "vpn" {
domain = "${var.domain}" zone_id = var.zone_id
name = "vpn" name = "vpn"
value = "${var.ips["tun0"]}" value = var.ips["tun0"]
type = "A" type = "A"
} }
resource "cloudflare_record" "vpn_wildcard" { resource "cloudflare_record" "vpn_wildcard" {
domain = "${var.domain}" zone_id = var.zone_id
name = "*.vpn.${var.domain}" name = "*.vpn.${var.domain}"
value = "${cloudflare_record.vpn.hostname}" value = cloudflare_record.vpn.hostname
type = "CNAME" type = "CNAME"
ttl = 3600 ttl = 3600
} }
/** /**
@ -85,25 +85,25 @@ resource "cloudflare_record" "vpn_wildcard" {
* *.vpn.bb8.fun * *.vpn.bb8.fun
*/ */
resource "cloudflare_record" "dovpn" { resource "cloudflare_record" "dovpn" {
domain = "${var.domain}" zone_id = var.zone_id
name = "dovpn" name = "dovpn"
value = "${var.ips["dovpn"]}" value = var.ips["dovpn"]
type = "A" type = "A"
} }
resource "cloudflare_record" "dovpn_wildcard" { resource "cloudflare_record" "dovpn_wildcard" {
domain = "${var.domain}" zone_id = var.zone_id
name = "*.dovpn.${var.domain}" name = "*.dovpn.${var.domain}"
value = "${cloudflare_record.dovpn.hostname}" value = cloudflare_record.dovpn.hostname
type = "CNAME" type = "CNAME"
ttl = 3600 ttl = 3600
} }
resource "cloudflare_record" "etcd" { resource "cloudflare_record" "etcd" {
domain = "${var.domain}" zone_id = var.zone_id
name = "etcd" name = "etcd"
value = "${var.ips["dovpn"]}" value = var.ips["dovpn"]
type = "A" type = "A"
} }
######################## ########################
@ -111,21 +111,21 @@ resource "cloudflare_record" "etcd" {
######################## ########################
resource "cloudflare_record" "mailgun-spf" { resource "cloudflare_record" "mailgun-spf" {
domain = "${var.domain}" zone_id = var.zone_id
name = "l" name = "l"
value = "v=spf1 include:mailgun.org ~all" value = "v=spf1 include:mailgun.org ~all"
type = "TXT" type = "TXT"
} }
resource "cloudflare_record" "mailgun-dkim" { resource "cloudflare_record" "mailgun-dkim" {
domain = "${var.domain}" zone_id = var.zone_id
name = "k1._domainkey.l" name = "k1._domainkey.l"
value = "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnbP+IQkuPkgmUhpqCKzIdDSZ0HazaMp+cdBH++LBed8oY8/jmV8BhxMp5JwyePzRTxneT8ASsRtcp7CQ3z4nMC7aFX0kH6Bnu2v+u2JWudxs8x0I02OrPbSaQ5QVQdbAaCUCEfCQ06LJsn8aqPNrRIOWEMnxln+ebFJ0wKGscFQIDAQAB" value = "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnbP+IQkuPkgmUhpqCKzIdDSZ0HazaMp+cdBH++LBed8oY8/jmV8BhxMp5JwyePzRTxneT8ASsRtcp7CQ3z4nMC7aFX0kH6Bnu2v+u2JWudxs8x0I02OrPbSaQ5QVQdbAaCUCEfCQ06LJsn8aqPNrRIOWEMnxln+ebFJ0wKGscFQIDAQAB"
type = "TXT" type = "TXT"
} }
resource "cloudflare_record" "mailgun-mxa" { resource "cloudflare_record" "mailgun-mxa" {
domain = "${var.domain}" zone_id = var.zone_id
name = "l" name = "l"
value = "mxa.mailgun.org" value = "mxa.mailgun.org"
type = "MX" type = "MX"
@ -133,7 +133,7 @@ resource "cloudflare_record" "mailgun-mxa" {
} }
resource "cloudflare_record" "mailgun-mxb" { resource "cloudflare_record" "mailgun-mxb" {
domain = "${var.domain}" zone_id = var.zone_id
name = "l" name = "l"
value = "mxb.mailgun.org" value = "mxb.mailgun.org"
type = "MX" type = "MX"
@ -141,9 +141,9 @@ resource "cloudflare_record" "mailgun-mxb" {
} }
resource "cloudflare_record" "k8s" { resource "cloudflare_record" "k8s" {
domain = "${var.domain}" zone_id = var.zone_id
name = "k8s" name = "k8s"
value = "10.8.0.1" value = "10.8.0.1"
type = "A" type = "A"
ttl = 3600 ttl = 3600
} }

7
cloudflare/providers.tf Normal file
View File

@ -0,0 +1,7 @@
terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
}
}
}

View File

@ -1,9 +1,10 @@
variable "domain" { variable "domain" {
type = "string" type = string
} }
variable "ips" { variable "ips" {
type = "map" type = map
} }
variable "droplet_ip" {} variable "droplet_ip" {}
variable "zone_id" {}

View File

@ -1,3 +1,11 @@
data "docker_network" "bridge" { data "docker_network" "bridge" {
name = "bridge" name = "bridge"
} }
data "cloudflare_zones" "bb8" {
filter {
name = "bb8"
lookup_type = "exact"
match = "bb8.fun"
}
}

View File

@ -4,7 +4,7 @@ resource "docker_network" "postgres" {
internal = true internal = true
ipam_config { ipam_config {
subnet = "172.20.0.8/29" subnet = "172.20.0.8/27"
gateway = "172.20.0.9" gateway = "172.20.0.9"
} }
} }

View File

@ -1,3 +1,4 @@
output "postgres-network-id" { output "postgres-network-id" {
value = "${docker_network.postgres.name}" value = docker_network.postgres.name
} }

View File

@ -1,18 +1,26 @@
resource "docker_container" "postgres" { resource "docker_container" "postgres" {
name = "postgres" name = "postgres"
image = "${docker_image.postgres.latest}" image = docker_image.postgres.image_id
command = [
"postgres",
"-c",
"max_connections=250",
"-c",
"shared_buffers=500MB",
]
volumes { volumes {
volume_name = "${docker_volume.postgres_volume.name}" volume_name = docker_volume.pg_data.name
container_path = "/var/lib/postgresql/data" container_path = "/var/lib/postgresql/data"
host_path = "${docker_volume.postgres_volume.mountpoint}" read_only = false
} }
// This is so that other host-only services can share this // This is so that other host-only services can share this
ports { ports {
internal = 5432 internal = 5432
external = 5432 external = 5432
ip = "${var.ips["eth0"]}" ip = var.ips["eth0"]
} }
// This is a not-so-great idea // This is a not-so-great idea
@ -20,10 +28,11 @@ resource "docker_container" "postgres" {
ports { ports {
internal = 5432 internal = 5432
external = 5432 external = 5432
ip = "${var.ips["tun0"]}" ip = var.ips["tun0"]
} }
memory = 256 memory = 2048
memory_swap = 2048
restart = "unless-stopped" restart = "unless-stopped"
destroy_grace_seconds = 10 destroy_grace_seconds = 10
must_run = true must_run = true
@ -32,12 +41,12 @@ resource "docker_container" "postgres" {
"POSTGRES_PASSWORD=${var.postgres-root-password}", "POSTGRES_PASSWORD=${var.postgres-root-password}",
] ]
networks = ["${docker_network.postgres.id}", "${data.docker_network.bridge.id}"] networks = [docker_network.postgres.id, data.docker_network.bridge.id]
} }
resource "docker_image" "postgres" { resource "docker_image" "postgres" {
name = "${data.docker_registry_image.postgres.name}" name = data.docker_registry_image.postgres.name
pull_triggers = ["${data.docker_registry_image.postgres.sha256_digest}"] pull_triggers = [data.docker_registry_image.postgres.sha256_digest]
} }
data "docker_registry_image" "postgres" { data "docker_registry_image" "postgres" {

10
db/providers.tf Normal file
View File

@ -0,0 +1,10 @@
terraform {
required_providers {
postgresql = {
source = "cyrilgdn/postgresql"
}
docker = {
source = "kreuzwerker/docker"
}
}
}

View File

@ -1,10 +1,11 @@
variable "postgres-version" { variable "postgres-version" {
description = "postgres version to use for fetching the docker image" description = "postgres version to use for fetching the docker image"
default = "10-alpine" default = "14-alpine"
} }
variable "ips" { variable "ips" {
type = "map" type = map(string)
} }
variable "postgres-root-password" {} variable "postgres-root-password" {
}

View File

@ -1,3 +1,3 @@
resource "docker_volume" "postgres_volume" { resource "docker_volume" "pg_data" {
name = "postgres_volume" name = "pg_data"
} }

View File

@ -1,5 +1,5 @@
resource "digitalocean_droplet" "sydney" { resource "digitalocean_droplet" "sydney" {
image = "" image = "??"
name = "sydney.captnemo.in" name = "sydney.captnemo.in"
region = "blr1" region = "blr1"
size = "s-1vcpu-2gb" size = "s-1vcpu-2gb"
@ -18,5 +18,6 @@ resource "digitalocean_droplet" "sydney" {
} }
output "droplet_ipv4" { output "droplet_ipv4" {
value = "${digitalocean_droplet.sydney.ipv4_address}" value = digitalocean_droplet.sydney.ipv4_address
} }

View File

@ -1,38 +1,35 @@
resource "digitalocean_firewall" "web" { resource "digitalocean_firewall" "web" {
name = "web-inbound" name = "web-inbound"
inbound_rule = [ inbound_rule {
{ protocol = "tcp"
protocol = "tcp" port_range = "80"
port_range = "80" source_addresses = ["0.0.0.0/0", "::/0"]
source_addresses = ["0.0.0.0/0", "::/0"] }
}, inbound_rule {
{ protocol = "tcp"
protocol = "tcp" port_range = "443"
port_range = "443" source_addresses = ["0.0.0.0/0", "::/0"]
source_addresses = ["0.0.0.0/0", "::/0"] }
},
]
} }
resource "digitalocean_firewall" "ssh" { resource "digitalocean_firewall" "ssh" {
name = "ssh-inbound" name = "ssh-inbound"
inbound_rule = [ inbound_rule {
{ protocol = "tcp"
protocol = "tcp" port_range = "22"
port_range = "22" source_addresses = ["0.0.0.0/0", "::/0"]
source_addresses = ["0.0.0.0/0", "::/0"] }
}, inbound_rule {
{ protocol = "tcp"
protocol = "tcp" port_range = "222"
port_range = "222" source_addresses = ["0.0.0.0/0", "::/0"]
source_addresses = ["0.0.0.0/0", "::/0"] }
}, inbound_rule {
{ protocol = "tcp"
protocol = "tcp" port_range = "24"
port_range = "24" source_addresses = ["0.0.0.0/0", "::/0"]
source_addresses = ["0.0.0.0/0", "::/0"] }
},
]
} }

View File

@ -1,4 +1,5 @@
resource "digitalocean_floating_ip" "sydney" { resource "digitalocean_floating_ip" "sydney" {
droplet_id = "${digitalocean_droplet.sydney.id}" droplet_id = digitalocean_droplet.sydney.id
region = "${digitalocean_droplet.sydney.region}" region = digitalocean_droplet.sydney.region
} }

19
digitalocean/providers.tf Normal file
View File

@ -0,0 +1,19 @@
terraform {
required_providers {
pass = {
source = "camptocamp/pass"
}
digitalocean = {
source = "digitalocean/digitalocean"
}
postgresql = {
source = "cyrilgdn/postgresql"
}
cloudflare = {
source = "cloudflare/cloudflare"
}
docker = {
source = "kreuzwerker/docker"
}
}
}

View File

@ -0,0 +1,72 @@
# Web must be converted manually. See https://docs.traefik.io/operations/api/
# Redirect on entry point "http" must be converted manually. See https://docs.traefik.io/middlewares/http/redirectscheme/
# TLS on entry point "https" must be converted manually. See https://docs.traefik.io/routing/routers/#tls
# The domain (bb8.fun) defined in the Docker provider must be converted manually. See https://docs.traefik.io/providers/docker/#defaultrule
# All the elements related to dynamic configuration (backends, frontends, ...) must be converted manually. See https://docs.traefik.io/routing/overview/
# The entry point (https) defined in the ACME configuration must be converted manually. See https://docs.traefik.io/routing/routers/#certresolver
[global]
sendAnonymousUsage = true
[tls.options]
[tls.options.default]
minVersion = "VersionTLS12"
[[tls.certificates]]
certFile = "/etc/traefik/git.captnemo.in.crt"
keyFile = "/etc/traefik/git.captnemo.in.key"
[[tls.certificates]]
certFile = "/etc/traefik/rss.captnemo.in.crt"
keyFile = "/etc/traefik/rss.captnemo.in.key"
# This forces port 8080
[api]
# https://doc.traefik.io/traefik/operations/dashboard/#insecure-mode
dashboard = true
# Enable the API in insecure mode, which means that the API will be available directly on the entryPoint named traefik.
insecure = true
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.http]
[entryPoints.https]
address = ":443"
[entryPoints.https.http]
[providers]
providersThrottleDuration = "2s"
[providers.docker]
watch = true
endpoint = "unix:///var/run/docker.sock"
swarmModeRefreshSeconds = "15s"
httpClientTimeout = "0s"
[providers.file]
[log]
[accessLog]
bufferingSize = 0
[certificatesResolvers]
[certificatesResolvers.default]
[certificatesResolvers.default.acme]
email = "acme@captnemo.in"
storage = "/acme/acme.json"
certificatesDuration = 0
[certificatesResolvers.default.acme.dnsChallenge]
provider = "cloudflare"
delayBeforeCheck = "2m0s"
[certificatesResolvers.default.acme.httpChallenge]
entryPoint = "http"
[certificatesResolvers.t]
[certificatesResolvers.t.acme]
email = "acme@captnemo.in"
storage = "/acme/acme.json"
[certificatesResolvers.myresolver.acme.tlsChallenge]
[http.middlewares]
[http.middlewares.test-redirectscheme.redirectScheme]
scheme = "https"
permanent = true

View File

@ -0,0 +1,26 @@
global:
sendAnonymousUsage: true
entryPoints:
http:
address: :80
https:
address: :443
providers:
providersThrottleDuration: 2s
docker:
watch: true
endpoint: unix:///var/run/docker.sock
swarmModeRefreshSeconds: 15s
file: {}
log: {}
accessLog: {}
certificatesResolvers:
default:
acme:
email: acme@captnemo.in
storage: /acme/acme.json
dnsChallenge:
provider: cloudflare
delayBeforeCheck: 2m0s
httpChallenge:
entryPoint: http

View File

@ -6,10 +6,6 @@ checkNewVersion = false
[accessLog] [accessLog]
[entryPoints] [entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https] [entryPoints.https]
address = ":443" address = ":443"
# This is required for ACME support # This is required for ACME support
@ -20,6 +16,9 @@ checkNewVersion = false
[[entryPoints.https.tls.certificates]] [[entryPoints.https.tls.certificates]]
certFile = "/etc/traefik/rss.captnemo.in.crt" certFile = "/etc/traefik/rss.captnemo.in.crt"
keyFile = "/etc/traefik/rss.captnemo.in.key" keyFile = "/etc/traefik/rss.captnemo.in.key"
[[entryPoints.https.tls.certificates]]
certFile = "/etc/traefik/tatooine.club.crt"
keyFile = "/etc/traefik/tatooine.club.key"
[docker] [docker]
# Make sure you mount this as readonly # Make sure you mount this as readonly
@ -38,33 +37,6 @@ checkNewVersion = false
# Since I can't apply a authentication # Since I can't apply a authentication
# on this yet # on this yet
[backends.elibsrv]
[backends.elibsrv.servers.default]
url = "http://elibsrv.captnemo.in:90"
[backends.scan]
[backends.scan.servers.default]
url = "http://scan.in.bb8.fun:90"
[frontends]
[frontends.scan]
backend = "scan"
[frontends.scan.headers]
SSLRedirect = true
SSLTemporaryRedirect = true
STSSeconds = 2592000
FrameDeny = true
ContentTypeNosniff = true
BrowserXssFilter = true
ReferrerPolicy = "no-referrer"
[frontends.scan.headers.customresponseheaders]
X-Powered-By = "Allomancy"
Server = "BlackBox"
X-Clacks-Overhead = "GNU Terry Pratchett"
[frontends.scan.routes.domain]
rule = "Host:scan.bb8.fun"
[web] [web]
address = ":1111" address = ":1111"
readOnly = true readOnly = true
@ -85,7 +57,8 @@ acmelogging = true
[acme.dnsChallenge] [acme.dnsChallenge]
provider = "cloudflare" provider = "cloudflare"
delayBeforeCheck = 30 delayBeforeCheck = 120
resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
# Primary 2 wildcard certs # Primary 2 wildcard certs
[[acme.domains]] [[acme.domains]]

View File

@ -9,3 +9,4 @@ data "docker_registry_image" "ubooquity" {
data "docker_registry_image" "lychee" { data "docker_registry_image" "lychee" {
name = "linuxserver/lychee:latest" name = "linuxserver/lychee:latest"
} }

View File

@ -6,22 +6,15 @@ data "docker_registry_image" "gotviz" {
# name = "${data.docker_registry_image.gotviz.name}" # name = "${data.docker_registry_image.gotviz.name}"
# pull_triggers = ["${data.docker_registry_image.gotviz.sha256_digest}"] # pull_triggers = ["${data.docker_registry_image.gotviz.sha256_digest}"]
# } # }
# resource "docker_container" "gotviz" { # resource "docker_container" "gotviz" {
# name = "gotviz" # name = "gotviz"
# image = "${docker_image.gotviz.latest}" # image = "${docker_image.gotviz.image_id}"
# labels = "${merge( # labels = "${merge(
# local.traefik_common_labels, map( # local.traefik_common_labels, map(
# "traefik.port", 8080, # "traefik.port", 8080,
# "traefik.frontend.rule","Host:got-relationships.${var.domain}" # "traefik.frontend.rule","Host:got-relationships.${var.domain}"
# ))}" # ))}"
# restart = "unless-stopped" # restart = "unless-stopped"
# destroy_grace_seconds = 60 # destroy_grace_seconds = 60
# must_run = true # must_run = true
# } # }

View File

@ -1,11 +1,11 @@
resource "docker_image" "traefik17" { resource "docker_image" "traefik17" {
name = "${data.docker_registry_image.traefik.name}" name = data.docker_registry_image.traefik.name
pull_triggers = ["${data.docker_registry_image.traefik.sha256_digest}"] pull_triggers = [data.docker_registry_image.traefik.sha256_digest]
} }
resource "docker_image" "ubooquity" { resource "docker_image" "ubooquity" {
name = "${data.docker_registry_image.ubooquity.name}" name = data.docker_registry_image.ubooquity.name
pull_triggers = ["${data.docker_registry_image.ubooquity.sha256_digest}"] pull_triggers = [data.docker_registry_image.ubooquity.sha256_digest]
} }
# resource "docker_image" "lychee" { # resource "docker_image" "lychee" {

View File

@ -1,20 +1,17 @@
locals { locals {
traefik_common_labels { traefik_common_labels = {
"traefik.enable" = "true" "traefik.enable" = "true"
// HSTS // HSTS
"traefik.frontend.headers.SSLTemporaryRedirect" = "true" "traefik.frontend.headers.SSLTemporaryRedirect" = "true"
"traefik.frontend.headers.STSSeconds" = "2592000" "traefik.frontend.headers.STSSeconds" = "2592000"
"traefik.frontend.headers.STSIncludeSubdomains" = "false" "traefik.frontend.headers.STSIncludeSubdomains" = "false"
// X-Powered-By, Server headers // X-Powered-By, Server headers
"traefik.frontend.headers.customResponseHeaders" = "${var.xpoweredby}" "traefik.frontend.headers.customResponseHeaders" = var.xpoweredby
// X-Frame-Options // X-Frame-Options
"traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" "traefik.frontend.headers.customFrameOptionsValue" = var.xfo_allow
"traefik.frontend.headers.contentTypeNosniff" = "true" "traefik.frontend.headers.contentTypeNosniff" = "true"
"traefik.frontend.headers.browserXSSFilter" = "true" "traefik.frontend.headers.browserXSSFilter" = "true"
"traefik.docker.network" = "traefik"
"traefik.docker.network" = "traefik"
} }
} }

View File

@ -1,6 +1,6 @@
# resource "docker_container" "lychee" { # resource "docker_container" "lychee" {
# name = "lychee" # name = "lychee"
# image = "${docker_image.lychee.latest}" # image = "${docker_image.lychee.image_id}"
# restart = "unless-stopped" # restart = "unless-stopped"
# destroy_grace_seconds = 10 # destroy_grace_seconds = 10
# must_run = true # must_run = true
@ -28,4 +28,3 @@
# ] # ]
# # links = ["${var.links-mariadb}"] # # links = ["${var.links-mariadb}"]
# } # }

View File

@ -1 +0,0 @@

View File

@ -3,3 +3,4 @@ resource "docker_network" "traefik" {
driver = "bridge" driver = "bridge"
internal = true internal = true
} }

View File

@ -3,13 +3,14 @@
# } # }
output "names-traefik" { output "names-traefik" {
value = "${docker_container.traefik.name}" value = docker_container.traefik.name
} }
output "traefik-network-id" { output "traefik-network-id" {
value = "${docker_network.traefik.id}" value = docker_network.traefik.id
} }
output "auth-header" { output "auth-header" {
value = "${var.basic_auth}" value = var.basic_auth
} }

19
docker/providers.tf Normal file
View File

@ -0,0 +1,19 @@
terraform {
required_providers {
pass = {
source = "camptocamp/pass"
}
digitalocean = {
source = "digitalocean/digitalocean"
}
postgresql = {
source = "cyrilgdn/postgresql"
}
cloudflare = {
source = "cloudflare/cloudflare"
}
docker = {
source = "kreuzwerker/docker"
}
}
}

View File

@ -1,70 +1,95 @@
resource "docker_container" "traefik" { resource "docker_container" "traefik" {
name = "traefik" name = "traefik"
image = "${docker_image.traefik17.latest}" image = docker_image.traefik17.image_id
# Admin Backend
ports { labels {
internal = 1111 label = "traefik.enable"
external = 1111 value = "true"
ip = "${var.ips["eth0"]}"
} }
ports { labels {
internal = 1111 label = "traefik.http.routers.api.rule"
external = 1111 value = "Host('traefik.in.bb8.fun')"
ip = "${var.ips["tun0"]}" }
labels {
label = "traefik.http.routers.api.service"
value = "api@internal"
} }
# Local Web Server # Local Web Server
ports { ports {
internal = 80 internal = 80
external = 80 external = 80
ip = "${var.ips["eth0"]}" ip = var.ips["eth0"]
} }
# Local Web Server (HTTPS) # Local Web Server (HTTPS)
ports { ports {
internal = 443 internal = 443
external = 443 external = 443
ip = "${var.ips["eth0"]}" ip = var.ips["eth0"]
} }
# Proxied via sydney.captnemo.in # Proxied via sydney.captnemo.in
ports { ports {
internal = 443 internal = 443
external = 443 external = 443
ip = "${var.ips["tun0"]}" ip = var.ips["tun0"]
} }
ports { ports {
internal = 80 internal = 80
external = 80 external = 80
ip = "${var.ips["tun0"]}" ip = var.ips["tun0"]
} }
upload { upload {
content = "${file("${path.module}/conf/traefik.toml")}" content = file("${path.module}/conf/traefik.toml")
file = "/etc/traefik/traefik.toml" file = "/etc/traefik/traefik.toml"
} }
upload { upload {
content = "${file("/home/nemo/projects/personal/certs/git.captnemo.in/fullchain.pem")}" content = file(
file = "/etc/traefik/git.captnemo.in.crt" "/home/nemo/projects/personal/certs/git.captnemo.in/fullchain.pem",
)
file = "/etc/traefik/git.captnemo.in.crt"
} }
upload { upload {
content = "${file("/home/nemo/projects/personal/certs/git.captnemo.in/privkey.pem")}" content = file(
file = "/etc/traefik/git.captnemo.in.key" "/home/nemo/projects/personal/certs/git.captnemo.in/privkey.pem",
)
file = "/etc/traefik/git.captnemo.in.key"
} }
upload { upload {
content = "${file("/home/nemo/projects/personal/certs/rss.captnemo.in/fullchain.pem")}" content = file(
file = "/etc/traefik/rss.captnemo.in.crt" "/home/nemo/projects/personal/certs/lego/certificates/tatooine.club.key",
)
file = "/etc/traefik/tatooine.club.key"
} }
upload { upload {
content = "${file("/home/nemo/projects/personal/certs/rss.captnemo.in/privkey.pem")}" content = file(
file = "/etc/traefik/rss.captnemo.in.key" "/home/nemo/projects/personal/certs/lego/certificates/tatooine.club.crt",
)
file = "/etc/traefik/tatooine.club.crt"
}
upload {
content = file(
"/home/nemo/projects/personal/certs/rss.captnemo.in/fullchain.pem",
)
file = "/etc/traefik/rss.captnemo.in.crt"
}
upload {
content = file(
"/home/nemo/projects/personal/certs/rss.captnemo.in/privkey.pem",
)
file = "/etc/traefik/rss.captnemo.in.key"
} }
volumes { volumes {
@ -85,17 +110,16 @@ resource "docker_container" "traefik" {
// `bridge` is auto-connected for now // `bridge` is auto-connected for now
// https://github.com/terraform-providers/terraform-provider-docker/issues/10 // https://github.com/terraform-providers/terraform-provider-docker/issues/10
networks = [ networks_advanced {
"${docker_network.traefik.id}", name = "traefik"
"${data.docker_network.bridge.id}", }
]
networks_advanced {
name = "bridge"
}
env = [ env = [
"CLOUDFLARE_EMAIL=${var.cloudflare_email}", "CLOUDFLARE_EMAIL=${var.cloudflare_email}",
"CLOUDFLARE_API_KEY=${var.cloudflare_key}", "CLOUDFLARE_API_KEY=${var.cloudflare_key}",
] ]
} }
data "docker_network" "bridge" {
name = "bridge"
}

View File

@ -1,6 +1,13 @@
locals {
l = merge(local.traefik_common_labels, {
"traefik.port" = 3000
"traefik.frontend.rule" = "Host:${var.domain}"
})
}
resource "docker_container" "ubooquity" { resource "docker_container" "ubooquity" {
name = "ubooquity" name = "ubooquity"
image = "${docker_image.ubooquity.latest}" image = docker_image.ubooquity.image_id
restart = "unless-stopped" restart = "unless-stopped"
destroy_grace_seconds = 30 destroy_grace_seconds = 30
@ -25,32 +32,37 @@ resource "docker_container" "ubooquity" {
host_path = "/mnt/xwing/media/EBooks/Comics" host_path = "/mnt/xwing/media/EBooks/Comics"
container_path = "/comics" container_path = "/comics"
} }
labels { labels {
"traefik.enable" = "true" label = "traefik.enable"
value = "true"
"traefik.admin.port" = 2203 }
"traefik.admin.frontend.rule" = "Host:library.${var.domain}" labels {
label = "traefik.admin.port"
# I do not trust the Ubooquity authentication value = 2203
# it does some shady JS encryption }
"traefik.admin.frontend.auth.basic" = "${var.basic_auth}" labels {
label = "traefik.admin.frontend.rule"
"traefik.read.port" = 2202 value = "Host:library.${var.domain}"
"traefik.read.frontend.rule" = "Host:read.${var.domain},comics.${var.domain},books.${var.domain}" }
labels {
"traefik.read.frontend.headers.SSLTemporaryRedirect" = "true" label = "traefik.admin.frontend.auth.basic"
"traefik.read.frontend.headers.STSSeconds" = "2592000" value = var.basic_auth
"traefik.read.frontend.headers.STSIncludeSubdomains" = "false" }
"traefik.read.frontend.headers.contentTypeNosniff" = "true" labels {
"traefik.read.frontend.headers.browserXSSFilter" = "true" label = "traefik.read.port"
"traefik.read.frontend.headers.customResponseHeaders" = "${var.xpoweredby}" value = 2202
"traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" }
"traefik.docker.network" = "traefik" labels {
label = "traefik.read.frontend.rule"
value = "Host:read.${var.domain},comics.${var.domain},books.${var.domain}"
}
labels {
label = "traefik.docker.network"
value = "traefik"
} }
upload { upload {
content = "${file("${path.module}/conf/ubooquity.json")}" content = file("${path.module}/conf/ubooquity.json")
file = "/config/preferences.json" file = "/config/preferences.json"
} }
@ -61,3 +73,4 @@ resource "docker_container" "ubooquity" {
"MAXMEM=800", "MAXMEM=800",
] ]
} }

View File

@ -1,18 +1,18 @@
variable "web_username" { variable "web_username" {
type = "string" type = string
} }
variable "web_password" { variable "web_password" {
type = "string" type = string
} }
variable "cloudflare_key" { variable "cloudflare_key" {
type = "string" type = string
description = "cloudflare API Key" description = "cloudflare API Key"
} }
variable "cloudflare_email" { variable "cloudflare_email" {
type = "string" type = string
description = "cloudflare email address" description = "cloudflare email address"
} }
@ -39,15 +39,15 @@ variable "refpolicy" {
} }
variable "wiki_session_secret" { variable "wiki_session_secret" {
type = "string" type = string
} }
variable "domain" { variable "domain" {
type = "string" type = string
} }
variable "ips" { variable "ips" {
type = "map" type = map(string)
} }
# variable "links-mariadb" {} # variable "links-mariadb" {}

View File

@ -1 +0,0 @@

View File

@ -1,11 +1,12 @@
module "echo-server" { module "echo-server" {
source = "modules/container" source = "./modules/container"
name = "echo-server" name = "echo-server"
image = "jmalloc/echo-server:latest" image = "jmalloc/echo-server:latest"
web { web = {
expose = "true" expose = "true"
port = 8080 port = 8080
host = "debug.${var.root-domain},debug.in.${var.root-domain}" host = "debug.${var.root-domain},debug.in.${var.root-domain}"
} }
} }

View File

@ -3,12 +3,12 @@ module "elibsrv" {
source = "./modules/container" source = "./modules/container"
image = "captn3m0/elibsrv" image = "captn3m0/elibsrv"
resource { resource = {
memory = 512 memory = 512
memory_swap = 512 memory_swap = 512
} }
web { web = {
expose = true expose = true
host = "ebooks.${var.root-domain}" host = "ebooks.${var.root-domain}"
auth = true auth = true
@ -40,12 +40,6 @@ module "elibsrv" {
"elibsrv_thumbheight=320", "elibsrv_thumbheight=320",
"elibsrv_title=Scarif Media Archives", "elibsrv_title=Scarif Media Archives",
] ]
networks_advanced = [ networks = ["bridge"]
{
name = "traefik"
},
{
name = "bridge"
},
]
} }

View File

@ -1,40 +0,0 @@
module "firefox-sync" {
name = "firefox-sync"
source = "./modules/container"
image = "mozilla/syncserver:latest"
// Default is port 80
web {
expose = true
port = "5000"
host = "firesync.${var.root-domain}"
}
resource {
memory = "400"
memory_swap = "400"
}
volumes = [{
host_path = "/mnt/xwing/data/firefox-sync"
container_path = "/data"
}]
env = [
"SYNCSERVER_PUBLIC_URL=https://firesync.${var.root-domain}",
"SYNCSERVER_SECRET=${data.pass_password.syncserver_secret.password}",
"SYNCSERVER_SQLURI=sqlite:////data/sync.db",
"SYNCSERVER_BATCH_UPLOAD_ENABLED=true",
"SYNCSERVER_FORCE_WSGI_ENVIRON=true",
"PORT=5000",
]
networks_advanced = [
{
name = "traefik"
},
{
name = "bridge"
},
]
}

View File

@ -2,12 +2,13 @@
; Copy required sections to your own app.ini (default is custom/conf/app.ini) ; Copy required sections to your own app.ini (default is custom/conf/app.ini)
; and modify as needed. ; and modify as needed.
; See the cheatsheet at https://docs.gitea.io/en-us/config-cheat-sheet/ ; See the cheatsheet at https://docs.gitea.io/en-us/config-cheat-sheet/
; A sample file with all configuration documented is at https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample ; A sample file with all configuration documented is at https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini
; App name that shows on every page title ; App name that shows on every page title
APP_NAME = Nemo's code APP_NAME = Nemo's code
RUN_MODE = prod RUN_MODE = prod
RUN_USER = git RUN_USER = git
WORK_PATH=/data/gitea
[repository] [repository]
ROOT = /data/git/repositories ROOT = /data/git/repositories
@ -17,6 +18,10 @@ USE_COMPAT_SSH_URI = false
TEMP_PATH = /data/gitea/uploads TEMP_PATH = /data/gitea/uploads
[ui] [ui]
;; Number of issues that are displayed on one page
ISSUE_PAGING_NUM = 20
; Value of `theme-color` meta tag, used by Android >= 5.0 ; Value of `theme-color` meta tag, used by Android >= 5.0
; An invalid color like "none" or "disable" will have the default style ; An invalid color like "none" or "disable" will have the default style
; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android ; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
@ -36,6 +41,11 @@ NOTICE_PAGING_NUM = 25
; Number of organization that are showed in one page ; Number of organization that are showed in one page
ORG_PAGING_NUM = 50 ORG_PAGING_NUM = 50
;; Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
;; A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
ONLY_SHOW_RELEVANT_REPOS = true
[ui.user] [ui.user]
; Number of repos that are showed in one page ; Number of repos that are showed in one page
REPO_PAGING_NUM = 15 REPO_PAGING_NUM = 15
@ -53,6 +63,9 @@ ENABLE_HARD_LINE_BREAK = false
CUSTOM_URL_SCHEMES = git,magnet,steam,irc,slack CUSTOM_URL_SCHEMES = git,magnet,steam,irc,slack
FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd
;; Enables math inline and block detection
ENABLE_MATH = true
; Define allowed algorithms and their minimum key length (use -1 to disable a type) ; Define allowed algorithms and their minimum key length (use -1 to disable a type)
[ssh.minimum_key_sizes] [ssh.minimum_key_sizes]
ED25519 = 256 ED25519 = 256
@ -60,6 +73,9 @@ ECDSA = 256
RSA = 2048 RSA = 2048
DSA = 1024 DSA = 1024
[lfs]
PATH=/data/gitea/lfs
[server] [server]
APP_DATA_PATH = /data/gitea APP_DATA_PATH = /data/gitea
HTTP_PORT = 3000 HTTP_PORT = 3000
@ -67,7 +83,6 @@ ROOT_URL = https://git.captnemo.in/
DISABLE_SSH = true DISABLE_SSH = true
DOMAIN = git.captnemo.in DOMAIN = git.captnemo.in
LFS_START_SERVER = true LFS_START_SERVER = true
LFS_CONTENT_PATH = /data/gitea/lfs
LFS_JWT_SECRET = "${lfs-jwt-secret}" LFS_JWT_SECRET = "${lfs-jwt-secret}"
OFFLINE_MODE = true OFFLINE_MODE = true
LANDING_PAGE = explore LANDING_PAGE = explore
@ -99,10 +114,7 @@ SQLITE_TIMEOUT = 500
; ITERATE_BUFFER_SIZE = 50 ; ITERATE_BUFFER_SIZE = 50
; Show the database generated SQL ; Show the database generated SQL
LOG_SQL = false LOG_SQL = false
SQLITE_JOURNAL_MODE = WAL
[session]
PROVIDER_CONFIG = /data/gitea/sessions
PROVIDER = file
[picture] [picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars AVATAR_UPLOAD_PATH = /data/gitea/avatars
@ -114,9 +126,11 @@ ISSUE_INDEXER_PATH = indexers/issues.bleve
; repo indexer by default disabled, since it uses a lot of disk space ; repo indexer by default disabled, since it uses a lot of disk space
REPO_INDEXER_ENABLED = true REPO_INDEXER_ENABLED = true
REPO_INDEXER_PATH = indexers/repos.bleve REPO_INDEXER_PATH = indexers/repos.bleve
UPDATE_BUFFER_LEN = 20
MAX_FILE_SIZE = 1048576 MAX_FILE_SIZE = 1048576
[queue.issue_indexer]
LENGTH = 100
[admin] [admin]
; Disable regular (non-admin) users to create organizations ; Disable regular (non-admin) users to create organizations
DISABLE_REGULAR_ORG_CREATION = false DISABLE_REGULAR_ORG_CREATION = false
@ -141,7 +155,7 @@ ACTIVE_CODE_LIVE_MINUTES = 15
RESET_PASSWD_CODE_LIVE_MINUTES = 30 RESET_PASSWD_CODE_LIVE_MINUTES = 30
REGISTER_EMAIL_CONFIRM = true REGISTER_EMAIL_CONFIRM = true
ENABLE_NOTIFY_MAIL = true ENABLE_NOTIFY_MAIL = true
DISABLE_REGISTRATION = false DISABLE_REGISTRATION = true
; ; Enable captcha validation for registration ; ; Enable captcha validation for registration
ENABLE_CAPTCHA = true ENABLE_CAPTCHA = true
REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA = true REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA = true
@ -150,7 +164,7 @@ CAPTCHA_TYPE = image
REQUIRE_SIGNIN_VIEW = false REQUIRE_SIGNIN_VIEW = false
; ; Default value for KeepEmailPrivate ; ; Default value for KeepEmailPrivate
; ; New user will get the value of this setting copied into their profile ; ; New user will get the value of this setting copied into their profile
DEFAULT_KEEP_EMAIL_PRIVATE = false DEFAULT_KEEP_EMAIL_PRIVATE = true
; ; Default value for AllowCreateOrganization ; ; Default value for AllowCreateOrganization
; ; New user will have rights set to create organizations depending on this setting ; ; New user will have rights set to create organizations depending on this setting
DEFAULT_ALLOW_CREATE_ORGANIZATION = true DEFAULT_ALLOW_CREATE_ORGANIZATION = true
@ -168,44 +182,39 @@ ENABLED = true
FROM = git@captnemo.in FROM = git@captnemo.in
USER = git@captnemo.in USER = git@captnemo.in
PASSWD = ${smtp_password} PASSWD = ${smtp_password}
HOST = smtp.migadu.com:587 PROTOCOL = smtps
SMTP_ADDR = smtp.migadu.com
SMTP_PORT = 465
SEND_AS_PLAIN_TEXT = true SEND_AS_PLAIN_TEXT = true
SUBJECT_PREFIX = "[git.captnemo.in] " SUBJECT_PREFIX = "[git.captnemo.in] "
[cache] [cache]
ADAPTER = redis ADAPTER = redis
INTERVAL = 60
HOST = "network=tcp,addr=gitea-redis:6379,db=0,pool_size=100,idle_timeout=180" HOST = "network=tcp,addr=gitea-redis:6379,db=0,pool_size=100,idle_timeout=180"
ITEM_TTL = 16h
[session] [session]
; ; Either "memory", "file", or "redis", default is "memory" ; ; Either "memory", "file", or "redis", default is "memory"
PROVIDER = redis PROVIDER = redis
; Provider config options
; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
PROVIDER_CONFIG = "network=tcp,addr=gitea-redis:6379,db=1,pool_size=100,idle_timeout=180" PROVIDER_CONFIG = "network=tcp,addr=gitea-redis:6379,db=1,pool_size=100,idle_timeout=180"
; ; Session cookie name
COOKIE_NAME = i_like_gitea
; ; If you use session in https only, default is false ; ; If you use session in https only, default is false
COOKIE_SECURE = true COOKIE_SECURE = true
; ; Enable set cookie, default is true ; SameSite settings. Either "none", "lax", or "strict"
ENABLE_SET_COOKIE = true SAME_SITE = strict
; ; Session GC time interval in seconds, default is 86400 (1 day)
; GC_INTERVAL_TIME = 86400
; ; Session life time in seconds, default is 86400 (1 day)
SESSION_LIFE_TIME = 2592000
[picture] [migrations]
ALLOWED_DOMAINS = github.com
ALLOW_LOCALNETWORKS = false
ENABLE_FEDERATED_AVATAR = true
[attachment] [attachment]
; ; Whether attachments are enabled. Defaults to `true` ; ; Whether attachments are enabled. Defaults to `true`
ENABLE = true ENABLE = true
; ; Path for attachments. Defaults to `data/attachments`
PATH = data/attachments
; ; One or more allowed types, e.g. image/jpeg|image/png ; ; One or more allowed types, e.g. image/jpeg|image/png
ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip|application/pdf|text/csv ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip|application/pdf|text/csv
; ; Max size of each file. Defaults to 32MB ; ; Max size of each file. Defaults to 32MB
MAX_SIZE = 20 MAX_SIZE = 200
; ; Max number of files per upload. Defaults to 10 ; ; Max number of files per upload. Defaults to 10
MAX_FILES = 10 MAX_FILES = 10
@ -216,11 +225,11 @@ MODE = console
; Buffer length of the channel, keep it as it is if you don't know what it is. ; Buffer length of the channel, keep it as it is if you don't know what it is.
BUFFER_LEN = 10000 BUFFER_LEN = 10000
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
LEVEL = Trace LEVEL = Warn
REDIRECT_MACARON_LOG = true REDIRECT_MACARON_LOG = true
ROUTER_LOG_LEVEL = Critical ROUTER_LOG_LEVEL = Critical
ENABLE_ACCESS_LOG = true logger.access.MODE=,
ENABLE_XORM_LOG = false logger.xorm.MODE=,
[cron] [cron]
; Enable running cron tasks periodically. ; Enable running cron tasks periodically.
@ -230,7 +239,7 @@ RUN_AT_START = false
[cron.archive_cleanup] [cron.archive_cleanup]
RUN_AT_START = true RUN_AT_START = true
SCHEDULE = @every 24h SCHEDULE = @midnight
; Archives created more than OLDER_THAN ago are subject to deletion ; Archives created more than OLDER_THAN ago are subject to deletion
OLDER_THAN = 24h OLDER_THAN = 24h
@ -241,7 +250,7 @@ SCHEDULE = @every 3h
; Repository health check ; Repository health check
[cron.repo_health_check] [cron.repo_health_check]
SCHEDULE = @every 24h SCHEDULE = @midnight
TIMEOUT = 60s TIMEOUT = 60s
; Arguments for command 'git fsck', e.g. "--unreachable --tags" ; Arguments for command 'git fsck', e.g. "--unreachable --tags"
; see more on http://git-scm.com/docs/git-fsck ; see more on http://git-scm.com/docs/git-fsck
@ -250,7 +259,7 @@ ARGS =
; Check repository statistics ; Check repository statistics
[cron.check_repo_stats] [cron.check_repo_stats]
RUN_AT_START = true RUN_AT_START = true
SCHEDULE = @every 24h SCHEDULE = @midnight
[api] [api]
; Max number of items will response in a page ; Max number of items will response in a page
@ -265,39 +274,40 @@ SHOW_FOOTER_TEMPLATE_LOAD_TIME = false
[openid] [openid]
ENABLE_OPENID_SIGNIN = true ENABLE_OPENID_SIGNIN = true
ENABLE_OPENID_SIGNUP = true ENABLE_OPENID_SIGNUP = false
[metrics] [metrics]
; Enables metrics endpoint. True or false; default is false. ; Enables metrics endpoint. True or false; default is false.
ENABLED = true ENABLED = true
; If you want to add authorization, specify a token here
; TODO
TOKEN =
[git]
; Disables highlight of added and removed changes
DISABLE_DIFF_HIGHLIGHT = false
; Max number of lines allowed in a single file in diff view
MAX_GIT_DIFF_LINES = 1000
; Max number of allowed characters in a line in diff view
MAX_GIT_DIFF_LINE_CHARACTERS = 5000
; Max number of files shown in diff view
MAX_GIT_DIFF_FILES = 100
; Arguments for command 'git gc', e.g. "--aggressive --auto"
; see more on http://git-scm.com/docs/git-gc/
GC_ARGS =
; Operation timeout in seconds
[git.timeout]
DEFAULT = 360
MIGRATE = 600
MIRROR = 300
CLONE = 300
PULL = 300
GC = 60
[oauth2] [oauth2]
ENABLE = false ENABLE = false
; this is same as JWT secret above ; this is same as JWT secret above
JWT_SECRET = "${oauth2-jwt-secret}" JWT_SECRET = "${oauth2-jwt-secret}"
[federation]
ENABLED=false
;; Enable/Disable user statistics for nodeinfo if federation is enabled
;SHARE_USER_STATISTICS = true
;;
;; Maximum federation request and response size (MB)
;MAX_SIZE = 4
;;
;; WARNING: Changing the settings below can break federation.
;;
;; HTTP signature algorithms
;ALGORITHMS = rsa-sha256, rsa-sha512, ed25519
;;
;; HTTP signature digest algorithm
;DIGEST_ALGORITHM = SHA-256
;;
;; GET headers for federation requests
;GET_HEADERS = (request-target), Date
;;
;; POST headers for federation requests
;POST_HEADERS = (request-target), Date, Digest
[packages]
;; Enable/Disable package registry capabilities
ENABLED = true

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.0"
width="2000.000000pt"
height="2000.000000pt"
viewBox="0 0 2000.000000 2000.000000"
preserveAspectRatio="xMidYMid meet"
id="svg10"
sodipodi:docname="favicon.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs14" />
<sodipodi:namedview
id="namedview12"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="pt"
showgrid="false"
inkscape:zoom="0.23281491"
inkscape:cx="1232.7389"
inkscape:cy="1415.2874"
inkscape:window-width="1920"
inkscape:window-height="1037"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
<metadata
id="metadata2">
Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata>
<g
transform="translate(0.000000,2000.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none"
id="g8"
style="fill:#000080">
<path
d="M0 10000 l0 -10000 10000 0 10000 0 0 10000 0 10000 -10000 0 -10000 0 0 -10000z m11852 5356 c553 -141 882 -698 738 -1251 -27 -102 -104 -261 -168 -346 -71 -94 -197 -207 -296 -265 -109 -65 -274 -121 -405 -136 l-100 -12 -90 -221 c-69 -169 -87 -222 -76 -227 12 -7 1420 -613 2145 -923 162 -69 310 -132 328 -140 31 -14 32 -16 20 -44 -7 -15 -55 -127 -107 -247 -52 -121 -96 -221 -98 -223 -4 -5 -131 48 -1385 585 -608 261 -1111 474 -1116 474 -5 0 -19 -24 -31 -52 -76 -181 -1440 -3576 -1474 -3667 -16 -43 -21 -81 -21 -166 -1 -99 2 -116 26 -167 38 -81 83 -133 158 -182 160 -104 244 -120 614 -113 383 7 564 38 731 125 90 47 218 173 263 258 67 128 79 306 32 471 -11 40 -20 75 -20 78 0 3 91 5 203 5 402 0 680 43 1017 156 226 76 540 218 768 348 35 20 66 36 68 36 9 0 3 -122 -11 -237 -57 -462 -214 -845 -470 -1152 -100 -119 -281 -291 -403 -383 -92 -70 -344 -228 -363 -228 -4 0 -35 29 -70 65 -105 109 -219 151 -345 125 -36 -7 -108 -38 -184 -78 -489 -261 -847 -376 -1345 -434 -180 -21 -653 -15 -955 11 -140 13 -338 25 -440 28 l-185 5 125 -126 125 -126 75 6 c97 8 170 -17 234 -82 65 -64 90 -137 82 -234 l-6 -75 206 -206 206 -207 83 6 c73 4 89 2 137 -20 184 -84 232 -302 100 -449 -67 -75 -110 -94 -212 -94 -68 0 -93 5 -125 22 -51 27 -119 100 -140 150 -19 43 -24 127 -12 188 l8 40 -201 200 -200 200 0 -531 0 -531 26 -14 c41 -22 101 -96 118 -146 38 -110 8 -222 -80 -302 -96 -88 -207 -103 -321 -45 -134 69 -192 232 -130 367 26 58 83 119 128 139 l29 13 0 531 0 532 -28 11 c-42 18 -108 89 -132 144 -24 53 -28 144 -10 191 11 30 9 32 -203 245 -117 119 -219 230 -226 246 -44 103 -170 239 -486 523 -412 371 -643 616 -819 865 -236 336 -397 688 -501 1092 -44 170 -80 249 -141 305 -76 70 -138 92 -263 95 l-106 2 -28 109 c-49 190 -70 366 -71 589 -1 220 10 324 54 505 61 246 161 471 308 691 134 200 315 410 326 378 3 -8 19 -68 36 -134 136 -520 354 -976 638 -1332 95 -119 277 -319 322 -354 l33 -25 -89 -49 c-166 -93 -288 -240 -324 -393 -15 -66 -15 -212 0 -289 24 -120 126 -300 267 -476 139 -172 374 -408 455 -456 181 -106 352 -125 492 -54 66 33 153 123 193 198 17 33 365 794 773 1690 408 897 760 1668 782 1715 72 154 120 262 116 265 -1 1 -91 40 -198 85 -321 136 -871 371 -935 400 -33 15 -161 70 -285 123 -735 312 -1076 459 -1082 466 -11 10 201 501 216 501 6 0 200 -81 431 -181 1489 -641 2052 -882 2070 -886 17 -3 33 24 118 212 l97 217 -48 61 c-96 122 -154 239 -194 392 -30 114 -36 323 -13 436 23 114 72 242 131 341 58 96 199 245 293 308 124 83 285 146 437 170 97 15 276 4 386 -24z"
id="path4"
style="fill:#192a56;fill-opacity:1" />
<path
d="M11496 14790 c-110 -28 -228 -126 -281 -234 -103 -210 -11 -470 203 -577 65 -33 71 -34 187 -34 116 0 122 1 187 34 82 41 169 128 204 206 99 217 11 466 -202 571 -66 33 -83 37 -166 40 -51 2 -110 -1 -132 -6z"
id="path6"
style="fill:#192a56;fill-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -18,3 +18,5 @@ User-agent: Xenus
Disallow: / Disallow: /
User-agent: Xenus Link Sleuth 1.1c User-agent: Xenus Link Sleuth 1.1c
Disallow: / Disallow: /
User-agent: AhrefsBot
Disallow: /

View File

@ -18,3 +18,5 @@ User-agent: Xenus
Disallow: / Disallow: /
User-agent: Xenus Link Sleuth 1.1c User-agent: Xenus Link Sleuth 1.1c
Disallow: / Disallow: /
User-agent: AhrefsBot
Disallow: /

View File

@ -1,6 +1,6 @@
# https://github.com/go-gitea/gitea/releases # https://github.com/go-gitea/gitea/releases
data "docker_registry_image" "gitea" { data "docker_registry_image" "gitea" {
name = "gitea/gitea:1.13" name = "gitea/gitea:1.21"
} }
data "docker_registry_image" "redis" { data "docker_registry_image" "redis" {
@ -8,14 +8,14 @@ data "docker_registry_image" "redis" {
} }
data "template_file" "gitea-config-file" { data "template_file" "gitea-config-file" {
template = "${file("${path.module}/conf/conf.ini.tpl")}" template = file("${path.module}/conf/conf.ini.tpl")
vars { vars = {
secret_key = "${var.secret-key}" secret_key = var.secret-key
internal_token = "${var.internal-token}" internal_token = var.internal-token
smtp_password = "${var.smtp-password}" smtp_password = var.smtp-password
lfs-jwt-secret = "${var.lfs-jwt-secret}" lfs-jwt-secret = var.lfs-jwt-secret
mysql-password = "${var.mysql-password}" mysql-password = var.mysql-password
oauth2-jwt-secret = "${var.oauth2-jwt-secret}" oauth2-jwt-secret = var.oauth2-jwt-secret
} }
} }

View File

@ -1,71 +1,89 @@
locals {
l = merge(var.traefik-labels, {
"traefik.port" = 3000
"traefik.frontend.rule" = "Host:${var.domain}"
})
}
resource "docker_container" "gitea" { resource "docker_container" "gitea" {
name = "gitea" name = "gitea"
image = "${docker_image.gitea.latest}" image = docker_image.gitea.image_id
labels = "${merge( dynamic "labels" {
var.traefik-labels, map( for_each = local.l
"traefik.port", 3000, content {
"traefik.frontend.rule", "Host:${var.domain}" label = labels.key
))}" value = labels.value
}
}
volumes { volumes {
volume_name = "${docker_volume.gitea_volume.name}" volume_name = docker_volume.gitea_volume.name
container_path = "/data" container_path = "/data"
host_path = "${docker_volume.gitea_volume.mountpoint}" host_path = docker_volume.gitea_volume.mountpoint
} }
# For the following uploads, note that
# /data/gitea is GITEA_CUSTOM_PATH
# Logos # Logos
# TODO: Add svg
# https://docs.gitea.com/next/administration/customizing-gitea#changing-the-logo
# PNG images
upload { upload {
content = "${file("${path.module}/conf/public/img/gitea-lg.png")}" content_base64 = filebase64("${path.module}/conf/public/img/gitea-lg.png")
file = "/data/gitea/public/img/gitea-lg.png" file = "/data/gitea/public/img/logo.png"
} }
upload { upload {
content = "${file("${path.module}/conf/public/img/gitea-sm.png")}" content_base64 = filebase64("${path.module}/conf/public/img/gitea-lg.png")
file = "/data/gitea/public/img/gitea-sm.png" file = "/data/gitea/public/img/apple-touch-icon.png"
} }
upload { upload {
content = "${file("${path.module}/conf/public/img/gitea-sm.png")}" content_base64 = filebase64("${path.module}/conf/public/img/gitea-sm.png")
file = "/data/gitea/public/img/favicon.png" file = "/data/gitea/public/img/favicon.png"
executable = false }
# SVG images
upload {
content_base64 = filebase64("${path.module}/conf/public/img/favicon.svg")
file = "/data/gitea/public/img/logo.svg"
} }
upload { upload {
content = "${file("${path.module}/../docker/conf/humans.txt")}" content_base64 = filebase64("${path.module}/conf/public/img/favicon.svg")
file = "/data/gitea/public/humans.txt" file = "/data/gitea/public/img/favicon.svg"
}
# Some files at top-level
upload {
content = file("${path.module}/../docker/conf/humans.txt")
file = "/data/gitea/humans.txt"
} }
upload { upload {
content = "${file("${path.module}/conf/public/robots.txt")}" content = file("${path.module}/conf/public/robots.txt")
file = "/data/gitea/public/robots.txt" file = "/data/gitea/robots.txt"
} }
# Extra Links in header # Extra Links in header
upload { upload {
content = "${file("${path.module}/conf/extra_links.tmpl")}" content = file("${path.module}/conf/extra_links.tmpl")
file = "/data/gitea/templates/custom/extra_links.tmpl" file = "/data/gitea/templates/custom/extra_links.tmpl"
} }
# This is the main configuration file # This is the main configuration file
upload { upload {
content = "${data.template_file.gitea-config-file.rendered}" content = data.template_file.gitea-config-file.rendered
file = "/data/gitea/conf/app.ini" file = "/data/gitea/conf/app.ini"
} }
memory = 512
memory = 800
restart = "always" restart = "always"
destroy_grace_seconds = 10 destroy_grace_seconds = 10
must_run = true must_run = true
networks = ["${docker_network.gitea.id}", "${var.traefik-network-id}"] networks = ["gitea", "traefik"]
# This doesn't work.
# See https://github.com/terraform-providers/terraform-provider-docker/issues/48
# lifecycle {
# ignore_changes = [
# "upload.2151376053.content",
# "upload.2151376053.executable",
# "upload.2151376053.file",
# ]
# }
} }
resource "docker_image" "gitea" { resource "docker_image" "gitea" {
name = "${data.docker_registry_image.gitea.name}" name = data.docker_registry_image.gitea.name
pull_triggers = ["${data.docker_registry_image.gitea.sha256_digest}"] pull_triggers = [data.docker_registry_image.gitea.sha256_digest]
} }

View File

@ -1 +0,0 @@

View File

@ -2,3 +2,4 @@ resource "docker_network" "gitea" {
name = "gitea" name = "gitea"
driver = "bridge" driver = "bridge"
} }

19
gitea/providers.tf Normal file
View File

@ -0,0 +1,19 @@
terraform {
required_providers {
pass = {
source = "camptocamp/pass"
}
digitalocean = {
source = "digitalocean/digitalocean"
}
postgresql = {
source = "cyrilgdn/postgresql"
}
cloudflare = {
source = "cloudflare/cloudflare"
}
docker = {
source = "kreuzwerker/docker"
}
}
}

View File

@ -1,6 +1,6 @@
resource "docker_container" "redis" { resource "docker_container" "redis" {
name = "gitea-redis" name = "gitea-redis"
image = "${docker_image.redis.latest}" image = docker_image.redis.image_id
volumes { volumes {
host_path = "/mnt/xwing/cache/gitea" host_path = "/mnt/xwing/cache/gitea"
@ -12,11 +12,12 @@ resource "docker_container" "redis" {
destroy_grace_seconds = 10 destroy_grace_seconds = 10
must_run = true must_run = true
networks = ["${docker_network.gitea.id}"] networks = [docker_network.gitea.id]
} }
resource "docker_image" "redis" { resource "docker_image" "redis" {
name = "${data.docker_registry_image.redis.name}" name = data.docker_registry_image.redis.name
pull_triggers = ["${data.docker_registry_image.redis.sha256_digest}"] pull_triggers = [data.docker_registry_image.redis.sha256_digest]
keep_locally = true keep_locally = true
} }

View File

@ -1,18 +1,32 @@
variable "traefik-labels" { variable "traefik-labels" {
type = "map" type = map(string)
} }
variable "domain" {} variable "domain" {
}
variable "ips" { variable "ips" {
type = "map" type = map(string)
} }
variable "secret-key" {} variable "secret-key" {
variable "internal-token" {} }
variable "smtp-password" {}
variable "lfs-jwt-secret" {} variable "internal-token" {
variable "oauth2-jwt-secret" {} }
variable "mysql-password" {}
variable "smtp-password" {
}
variable "lfs-jwt-secret" {
}
variable "oauth2-jwt-secret" {
}
variable "mysql-password" {
}
variable "traefik-network-id" {
}
variable "traefik-network-id" {}

View File

@ -1,3 +1,4 @@
resource "docker_volume" "gitea_volume" { resource "docker_volume" "gitea_volume" {
name = "gitea_volume" name = "gitea_volume"
} }

24
home-assistant/main.tf Normal file
View File

@ -0,0 +1,24 @@
module "home-assistant" {
name = "home-assistant"
source = "../modules/container"
image = "ghcr.io/home-assistant/home-assistant:stable"
resource = {
memory = 1024
memory_swap = 1024
}
env = [
"TZ=Asia/Kolkata",
]
network_mode = "host"
volumes = [
{
container_path = "/config"
host_path = "/mnt/zwing/config/home-assistant"
},
]
}

View File

@ -1,13 +1,16 @@
# module "jupyter" { module "jupyter" {
# name = "jupyter" name = "jupyter"
# source = "modules/container" source = "./modules/container"
# image = "jupyter/tensorflow-notebook" image = "jupyter/scipy-notebook"
# ports = [ resource = {
# { memory = 1024
# internal = 8888 memory_swap = 4096
# external = 1112 }
# ip = "${var.ips["tun0"]}" web = {
# }, expose = "true"
# ] host = "j.${var.root-domain}"
# } port = 8888
}
networks = ["bridge"]
gpu = true
}

View File

@ -1,15 +1,15 @@
# kaarana related stuff # kaarana related stuff
module "kaarana" { # module "kaarana" {
source = "./kaarana" # source = "./kaarana"
root_db_password = "${data.pass_password.kaarana-root-db-password.password}" # root_db_password = data.pass_password.kaarana-root-db-password.password
db_password = "${data.pass_password.kaarana-db-password.password}" # db_password = data.pass_password.kaarana-db-password.password
providers = { # providers = {
docker = "docker.sydney" # docker = docker.sydney
} # }
} # }
data "pass_password" "kaarana-root-db-password" { data "pass_password" "kaarana-root-db-password" {
path = "KAARANA_DB_ROOT_PASSWORD" path = "KAARANA_DB_ROOT_PASSWORD"
@ -18,3 +18,4 @@ data "pass_password" "kaarana-root-db-password" {
data "pass_password" "kaarana-db-password" { data "pass_password" "kaarana-db-password" {
path = "KAARANA_DB_PASSWORD" path = "KAARANA_DB_PASSWORD"
} }

View File

@ -18,7 +18,7 @@ resource "docker_network" "kaarana-db" {
// Run a small mySQL container in this subnet // Run a small mySQL container in this subnet
resource "docker_container" "mysql" { resource "docker_container" "mysql" {
image = "${docker_image.db.latest}" image = docker_image.db.image_id
name = "kaarana-mariadb" name = "kaarana-mariadb"
restart = "always" restart = "always"
must_run = true must_run = true
@ -35,8 +35,6 @@ resource "docker_container" "mysql" {
container_path = "/var/lib/mysql" container_path = "/var/lib/mysql"
} }
networks_advanced { networks = ["kaarana-db"]
name = "kaarana-db"
aliases = ["${local.db_hostname}"]
}
} }

View File

@ -4,7 +4,7 @@ data "docker_registry_image" "wp" {
resource "docker_image" "wp" { resource "docker_image" "wp" {
name = "wordpress" name = "wordpress"
pull_triggers = ["${data.docker_registry_image.wp.sha256_digest}"] pull_triggers = [data.docker_registry_image.wp.sha256_digest]
} }
data "docker_registry_image" "db" { data "docker_registry_image" "db" {
@ -13,7 +13,7 @@ data "docker_registry_image" "db" {
resource "docker_image" "db" { resource "docker_image" "db" {
name = "mariadb" name = "mariadb"
pull_triggers = ["${data.docker_registry_image.db.sha256_digest}"] pull_triggers = [data.docker_registry_image.db.sha256_digest]
} }
data "docker_registry_image" "traefik" { data "docker_registry_image" "traefik" {
@ -22,5 +22,6 @@ data "docker_registry_image" "traefik" {
resource "docker_image" "traefik" { resource "docker_image" "traefik" {
name = "traefik" name = "traefik"
pull_triggers = ["${data.docker_registry_image.db.sha256_digest}"] pull_triggers = [data.docker_registry_image.db.sha256_digest]
} }

View File

@ -12,7 +12,7 @@ resource "docker_network" "traefik" {
resource "docker_container" "traefik" { resource "docker_container" "traefik" {
name = "traefik" name = "traefik"
image = "${docker_image.traefik.latest}" image = docker_image.traefik.image_id
# Do not offer HTTP2 # Do not offer HTTP2
# https://community.containo.us/t/traefikv2-http-2-0/1199 # https://community.containo.us/t/traefikv2-http-2-0/1199
@ -21,7 +21,7 @@ resource "docker_container" "traefik" {
] ]
upload { upload {
content = "${file("${path.module}/traefik.toml")}" content = file("${path.module}/traefik.toml")
file = "/etc/traefik/traefik.toml" file = "/etc/traefik/traefik.toml"
} }
@ -53,12 +53,12 @@ resource "docker_container" "traefik" {
destroy_grace_seconds = 10 destroy_grace_seconds = 10
must_run = true must_run = true
networks_advanced = [ networks_advanced {
{ name = "bridge"
name = "bridge" }
},
{ networks_advanced {
name = "traefik" name = "traefik"
}, }
]
} }

View File

@ -1,8 +1,12 @@
variable "root_db_password" {} variable "root_db_password" {
variable "db_password" {} }
variable "db_password" {
}
locals { locals {
username = "wordpress" username = "wordpress"
database = "wordpress" database = "wordpress"
db_hostname = "kaarana.db" db_hostname = "kaarana.db"
} }

View File

@ -1,18 +1,16 @@
resource "docker_container" "wp" { resource "docker_container" "wp" {
image = "${docker_image.wp.latest}" image = docker_image.wp.image_id
name = "kaarana-wordpress" name = "kaarana-wordpress"
restart = "always" restart = "always"
must_run = true must_run = true
labels { labels = {
"traefik.enable" = "true" "traefik.enable" = "true"
"traefik.tcp.routers.kaarana.rule" = "HostSNI(`kaarana.captnemo.in`)" "traefik.tcp.routers.kaarana.rule" = "HostSNI(`kaarana.captnemo.in`)"
"traefik.tcp.routers.kaarana.tls" = "true" "traefik.tcp.routers.kaarana.tls" = "true"
# "traefik.tcp.routers.kaarana.tls.options" = "foo" # "traefik.tcp.routers.kaarana.tls.options" = "foo"
"traefik.tcp.services.wordpress.loadbalancer.server.port" = "80" "traefik.tcp.services.wordpress.loadbalancer.server.port" = "80"
# "traefik.tcp.routers.kaarana.entrypoints" = "web-secure" # "traefik.tcp.routers.kaarana.entrypoints" = "web-secure"
"traefik.tcp.routers.kaarana.tls.certResolver" = "default" "traefik.tcp.routers.kaarana.tls.certResolver" = "default"
"traefik.tcp.routers.kaarana.tls.domains[0].main" = "kaarana.captnemo.in" "traefik.tcp.routers.kaarana.tls.domains[0].main" = "kaarana.captnemo.in"
@ -37,17 +35,6 @@ resource "docker_container" "wp" {
ip = "10.8.0.1" ip = "10.8.0.1"
} }
networks_advanced = [ networks = ["bridge", "kaarana-db"]
{
name = "kaarana-db"
},
{
// TODO: Once configuration/plugins have stabilized
// remove internet access from wordpress
name = "bridge"
},
{
name = "traefik"
},
]
} }

33
kavita.tf Normal file
View File

@ -0,0 +1,33 @@
# module "kavita" {
# name = "kavita"
# source = "./modules/container"
# image = "kizaing/kavita:latest"
# web = {
# expose = true
# port = 5000
# host = "kavita.bb8.fun"
# }
# resource = {
# memory = 1024
# memory_swap = 1024
# }
# volumes = [
# {
# host_path = "/mnt/xwing/media/EBooks"
# container_path = "/ebooks"
# },
# {
# host_path = "/mnt/xwing/config/kavita"
# container_path = "/kavita/config"
# }
# ]
# networks = ["traefik"]
# env = [
# "TZ=Asia/Kolkata",
# ]
# }

View File

@ -39,4 +39,3 @@
# type = "A" # type = "A"
# ttl = 120 # ttl = 120
# } # }

View File

@ -1,20 +1,20 @@
module "klaxon-db" { module "klaxon-db" {
source = "modules/postgres" source = "./modules/postgres"
name = "klaxon" name = "klaxon"
password = "${data.pass_password.klaxon-db-password.password}" password = data.pass_password.klaxon-db-password.password
} }
module "klaxon" { module "klaxon" {
name = "klaxon" name = "klaxon"
source = "modules/container" source = "./modules/container"
web { web = {
expose = true expose = true
port = "3000" port = "3000"
host = "klaxon.${var.root-domain}" host = "klaxon.${var.root-domain}"
} }
resource { resource = {
memory = 1024 memory = 1024
memory_swap = 1024 memory_swap = 1024
} }
@ -29,18 +29,12 @@ module "klaxon" {
"KLAXON_FORCE_SSL=false", "KLAXON_FORCE_SSL=false",
"KLAXON_COMPILE_ASSETS=true", "KLAXON_COMPILE_ASSETS=true",
"ADMIN_EMAILS=klaxon@captnemo.in", "ADMIN_EMAILS=klaxon@captnemo.in",
"MAILER_FROM_ADDRESS=klaxon@sendgrid.captnemo.in" "MAILER_FROM_ADDRESS=klaxon@sendgrid.captnemo.in",
] ]
restart = "always" restart = "always"
image = "themarshallproject/klaxon" image = "themarshallproject/klaxon"
networks_advanced = [ networks = ["postgres", "external"]
{
name = "traefik"
}, {
name = "postgres"
}, {
name = "external"
}]
} }

View File

@ -17,4 +17,3 @@
# } # }
# } # }
# } # }

112
main.tf
View File

@ -1,96 +1,112 @@
module "cloudflare" { module "cloudflare" {
source = "cloudflare" source = "./cloudflare"
domain = "bb8.fun" domain = "bb8.fun"
ips = "${var.ips}" zone_id = lookup(data.cloudflare_zones.bb8.zones[0], "id")
ips = var.ips
droplet_ip = "${module.digitalocean.droplet_ipv4}" droplet_ip = module.digitalocean.droplet_ipv4
} }
module "docker" { module "docker" {
source = "docker" source = "./docker"
web_username = "${data.pass_password.web_username.password}" web_username = data.pass_password.web_username.password
web_password = "${data.pass_password.web_password.password}" web_password = data.pass_password.web_password.password
cloudflare_key = "${data.pass_password.cloudflare_key.password}" cloudflare_key = data.pass_password.cloudflare_key.password
cloudflare_email = "bb8@captnemo.in" cloudflare_email = "bb8@captnemo.in"
wiki_session_secret = "${data.pass_password.wiki_session_secret.password}" wiki_session_secret = data.pass_password.wiki_session_secret.password
ips = "${var.ips}" ips = var.ips
domain = "bb8.fun" domain = "bb8.fun"
} }
module "db" { module "db" {
source = "db" source = "./db"
postgres-root-password = "${data.pass_password.postgres-root-password.password}" postgres-root-password = data.pass_password.postgres-root-password.password
ips = "${var.ips}" ips = var.ips
} }
module "timemachine" { module "timemachine" {
source = "timemachine" source = "./timemachine"
ips = "${var.ips}" ips = var.ips
username-1 = "vikalp" username-1 = "vikalp"
username-2 = "rishav" username-2 = "rishav"
password-1 = "${data.pass_password.timemachine-password-1.password}" password-1 = data.pass_password.timemachine-password-1.password
password-2 = "${data.pass_password.timemachine-password-2.password}" password-2 = data.pass_password.timemachine-password-2.password
} }
module "gitea" { module "gitea" {
source = "gitea" source = "./gitea"
domain = "git.captnemo.in" domain = "git.captnemo.in"
traefik-labels = "${var.traefik-common-labels}" traefik-labels = var.traefik-common-labels
ips = "${var.ips}" ips = var.ips
secret-key = "${data.pass_password.gitea-secret-key.password}" secret-key = data.pass_password.gitea-secret-key.password
internal-token = "${data.pass_password.gitea-internal-token.password}" internal-token = data.pass_password.gitea-internal-token.password
smtp-password = "${data.pass_password.gitea-smtp-password.password}" smtp-password = data.pass_password.gitea-smtp-password.password
lfs-jwt-secret = "${data.pass_password.gitea-lfs-jwt-secret.password}" lfs-jwt-secret = data.pass_password.gitea-lfs-jwt-secret.password
oauth2-jwt-secret = "${data.pass_password.gitea-oauth2-jwt-secret.password}" oauth2-jwt-secret = data.pass_password.gitea-oauth2-jwt-secret.password
//passed, but not used //passed, but not used
mysql-password = "" mysql-password = ""
traefik-network-id = "${module.docker.traefik-network-id}" traefik-network-id = module.docker.traefik-network-id
} }
module "opml" { module "opml" {
source = "opml" source = "./opml"
domain = "opml.bb8.fun" domain = "opml.bb8.fun"
client-id = "${data.pass_password.opml-github-client-id.password}" client-id = data.pass_password.opml-github-client-id.password
client-secret = "${data.pass_password.opml-github-client-secret.password}" client-secret = data.pass_password.opml-github-client-secret.password
traefik-network-id = "${module.docker.traefik-network-id}" traefik-network-id = module.docker.traefik-network-id
} }
module "radicale" { module "radicale" {
source = "radicale" source = "./radicale"
domain = "radicale.bb8.fun" domain = "radicale.bb8.fun"
} }
module "media" { module "media" {
source = "media" source = "./media"
domain = "bb8.fun" domain = "bb8.fun"
traefik-labels = "${var.traefik-common-labels}" traefik-labels = var.traefik-common-labels
ips = "${var.ips}" ips = var.ips
traefik-network-id = "${module.docker.traefik-network-id}" # ToDO: Change this to lookup
lastfm_api_key = "${data.pass_password.navidrome-lastfm-api-key.password}" traefik-network-id = "ffc1e366849e"
lastfm_secret = "${data.pass_password.navidrome-lastfm-secret.password}" lastfm_api_key = data.pass_password.navidrome-lastfm-api-key.password
spotify_id = "${data.pass_password.navidrome-spotify-id.password}" lastfm_secret = data.pass_password.navidrome-lastfm-secret.password
spotify_secret = "${data.pass_password.navidrome-spotify-secret.password}" spotify_id = data.pass_password.navidrome-spotify-id.password
spotify_secret = data.pass_password.navidrome-spotify-secret.password
} }
module "monitoring" { module "monitoring" {
source = "monitoring" source = "./monitoring"
gf-security-admin-password = "${data.pass_password.gf-security-admin-password.password}" gf-security-admin-password = data.pass_password.gf-security-admin-password.password
domain = "bb8.fun" domain = "bb8.fun"
transmission = "${module.media.names-transmission}" transmission = module.media.names-transmission
traefik-labels = "${var.traefik-common-labels}" traefik-labels = var.traefik-common-labels
ips = "${var.ips}" ips = var.ips
links-traefik = "${module.docker.names-traefik}" links-traefik = module.docker.names-traefik
traefik-network-id = "${module.docker.traefik-network-id}" traefik-network-id = module.docker.traefik-network-id
} }
module "digitalocean" { module "digitalocean" {
source = "digitalocean" source = "./digitalocean"
}
module "home-assistant" {
source = "./home-assistant"
}
module "mastodon" {
source = "./mastodon"
db-password = data.pass_password.mastodon-db-password.password
secret-key-base = data.pass_password.mastodon-secret-key-base.password
otp-secret = data.pass_password.mastodon-otp-secret.password
vapid-private-key = data.pass_password.mastodon-vapid-private-key.password
vapid-public-key = data.pass_password.mastodon-vapid-public-key.password
smtp-password = data.pass_password.mastodon-smtp-password.password
} }
// Used to force access to ISP related resources // Used to force access to ISP related resources
# module "tinyproxy" { # module "tinyproxy" {
# source = "tinyproxy" # source = "./tinyproxy"
# ips = "${var.ips}" # ips = "${var.ips}"
# } # }

29
mastodon/db.tf Normal file
View File

@ -0,0 +1,29 @@
module "mastodon-redis" {
name = "mastodon-redis"
source = "../modules/container"
image = "redis:alpine"
networks = ["mastodon"]
keep_image = true
resource = {
memory = 256
memory_swap = 256
}
# In case the cache dies,
# tootctl feeds build
# regenerates the feeds, run it from
# inside a mastodon container
volumes = [
{
host_path = "/mnt/zwing/cache/mastodon-redis"
container_path = "/data"
}
]
}
module "mastodon-db" {
source = "../modules/postgres"
name = "mastodon"
password = var.db-password
}

23
mastodon/locals.tf Normal file
View File

@ -0,0 +1,23 @@
locals {
version = "4.1.10"
env = [
"LOCAL_DOMAIN=tatooine.club",
"REDIS_HOST=mastodon-redis",
"REDIS_PORT=6379",
"DB_HOST=postgres",
"DB_USER=mastodon",
"DB_NAME=mastodon",
"DB_PASS=${var.db-password}",
"DB_PORT=5432",
"ES_ENABLED=false",
"SECRET_KEY_BASE=${var.secret-key-base}",
"OTP_SECRET=${var.otp-secret}",
"VAPID_PRIVATE_KEY=${var.vapid-private-key}",
"VAPID_PUBLIC_KEY=${var.vapid-public-key}",
"SMTP_SERVER=smtp.eu.mailgun.org",
"SMTP_PORT=587",
"SMTP_LOGIN=mastodon@mail.tatooine.club",
"SMTP_PASSWORD=${var.smtp-password}",
"SMTP_FROM_ADDRESS=mastodon@mail.tatooine.club",
]
}

103
mastodon/main.tf Normal file
View File

@ -0,0 +1,103 @@
module "mastodon-web" {
name = "mastodon-web"
source = "../modules/container"
image = "ghcr.io/mastodon/mastodon:v${local.version}"
keep_image = true
networks = ["mastodon", "traefik", "external", "postgres"]
labels = {
"traefik.frontend.headers.STSPreload" = "true"
"traefik.frontend.headers.STSIncludeSubdomains" = "true"
"traefik.frontend.headers.STSSeconds" = "31536000"
}
env = concat(local.env,[
"MAX_THREADS=4",
"WEB_CONCURRENCY=5"
])
command = [
"bash",
"-c",
"rm -f /mastodon/tmp/pids/server.pid; bundle exec rake db:migrate; bundle exec rails s -p 3000"
]
volumes = [{
container_path = "/mastodon/public/system"
host_path = "/mnt/xwing/data/mastodon"
}]
web = {
expose = "true"
host = "tatooine.club"
port = 3000
}
resource = {
memory = 2048
memory_swap = 2048
}
}
module "mastodon-streaming" {
name = "mastodon-streaming"
source = "../modules/container"
image = "ghcr.io/mastodon/mastodon:v${local.version}"
keep_image = true
# 24 threads for Streaming
env = concat(local.env,[
"DB_POOL=8",
"STREAMING_CLUSTER_NUM=4"
])
networks = ["postgres", "external", "mastodon"]
command = [
"node",
"./streaming"
]
web = {
expose = "false"
}
resource = {
memory = 512
memory_swap = 512
}
}
module "mastodon-sidekiq" {
name = "mastodon-sidekiq"
source = "../modules/container"
image = "ghcr.io/mastodon/mastodon:v${local.version}"
keep_image = true
env = concat(local.env,[
"DB_POOL=50"
])
web = {
expose = "false"
}
networks = ["postgres", "external", "mastodon"]
command = [
"bundle",
"exec",
"sidekiq"
]
volumes = [{
container_path = "/mastodon/public/system"
host_path = "/mnt/xwing/data/mastodon"
}]
resource = {
memory = 2048
memory_swap = 2048
}
}

5
mastodon/network.tf Normal file
View File

@ -0,0 +1,5 @@
resource "docker_network" "mastodon" {
name = "mastodon"
driver = "bridge"
internal = true
}

10
mastodon/provider.tf Normal file
View File

@ -0,0 +1,10 @@
terraform {
required_providers {
postgresql = {
source = "cyrilgdn/postgresql"
}
docker = {
source = "kreuzwerker/docker"
}
}
}

18
mastodon/vars.tf Normal file
View File

@ -0,0 +1,18 @@
variable "db-password" {
type = string
}
variable "secret-key-base" {
type = string
}
variable "otp-secret" {
type = string
}
variable "vapid-private-key" {
type = string
}
variable "vapid-public-key" {
type = string
}
variable "smtp-password" {
type = string
}

View File

@ -2,43 +2,34 @@
# source = "../modules/container" # source = "../modules/container"
# image = "linuxserver/airsonic:latest" # image = "linuxserver/airsonic:latest"
# name = "airsonic" # name = "airsonic"
# resource { # resource {
# memory = "1024" # memory = "1024"
# memory_swap = "1024" # memory_swap = "1024"
# } # }
# web { # web {
# port = 4040 # port = 4040
# host = "airsonic.bb8.fun" # host = "airsonic.bb8.fun"
# expose = true # expose = true
# } # }
# networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" # networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}"
# env = [ # env = [
# "PUID=1004", # "PUID=1004",
# "PGID=1003", # "PGID=1003",
# "TZ=Asia/Kolkata", # "TZ=Asia/Kolkata",
# "JAVA_OPTS=-Xmx512m -Dserver.use-forward-headers=true -Dserver.context-path=/", # "JAVA_OPTS=-Xmx512m -Dserver.use-forward-headers=true -Dserver.context-path=/",
# ] # ]
# devices = [{ # devices = [{
# host_path = "/dev/snd" # host_path = "/dev/snd"
# container_path = "/dev/snd" # container_path = "/dev/snd"
# }] # }]
# # files = [ # # files = [
# # "/usr/lib/jvm/java-1.8-openjdk/jre/lib/airsonic.properties", # # "/usr/lib/jvm/java-1.8-openjdk/jre/lib/airsonic.properties",
# # "/usr/lib/jvm/java-1.8-openjdk/jre/lib/sound.properties", # # "/usr/lib/jvm/java-1.8-openjdk/jre/lib/sound.properties",
# # ] # # ]
# # contents = [ # # contents = [
# # "${data.template_file.airsonic-properties-file.rendered}", # # "${data.template_file.airsonic-properties-file.rendered}",
# # "${file("${path.module}/conf/airsonic.sound.properties")}", # # "${file("${path.module}/conf/airsonic.sound.properties")}",
# # ] # # ]
# volumes = [ # volumes = [
# { # {
# host_path = "/mnt/xwing/config/airsonic2" # host_path = "/mnt/xwing/config/airsonic2"
@ -62,16 +53,10 @@
# }, # },
# ] # ]
# } # }
# data "template_file" "airsonic-properties-file" { # data "template_file" "airsonic-properties-file" {
# template = "${file("${path.module}/conf/airsonic.properties.tpl")}" # template = "${file("${path.module}/conf/airsonic.properties.tpl")}"
# vars { # vars {
# smtp-password = "${var.airsonic-smtp-password}" # smtp-password = "${var.airsonic-smtp-password}"
# # db-password = "${var.airsonic-db-password}" # # db-password = "${var.airsonic-db-password}"
# } # }
# } # }

View File

@ -10,17 +10,17 @@
"bind-address-ipv6": "::", "bind-address-ipv6": "::",
"blocklist-enabled": true, "blocklist-enabled": true,
"blocklist-url": "http://john.bitsurge.net/public/biglist.p2p.gz", "blocklist-url": "http://john.bitsurge.net/public/biglist.p2p.gz",
"cache-size-mb": 16, "cache-size-mb": 256,
"dht-enabled": true, "dht-enabled": true,
"download-dir": "/downloads", "download-dir": "/downloads",
"download-queue-enabled": true, "download-queue-enabled": false,
"download-queue-size": 5, "download-queue-size": 5,
"encryption": 1, "encryption": 1,
"idle-seeding-limit": 30, "idle-seeding-limit": 30,
"idle-seeding-limit-enabled": false, "idle-seeding-limit-enabled": false,
"incomplete-dir": "/downloads", "incomplete-dir": "/downloads",
"incomplete-dir-enabled": true, "incomplete-dir-enabled": true,
"lpd-enabled": false, "lpd-enabled": true,
"message-level": 2, "message-level": 2,
"peer-congestion-algorithm": "", "peer-congestion-algorithm": "",
"peer-id-ttl-hours": 6, "peer-id-ttl-hours": 6,
@ -31,13 +31,13 @@
"peer-port-random-low": 49152, "peer-port-random-low": 49152,
"peer-port-random-on-start": false, "peer-port-random-on-start": false,
"peer-socket-tos": "default", "peer-socket-tos": "default",
"pex-enabled": true, "pex-enabled": false,
"port-forwarding-enabled": true, "port-forwarding-enabled": true,
"preallocation": 1, "preallocation": 1,
"prefetch-enabled": true, "prefetch-enabled": true,
"queue-stalled-enabled": true, "queue-stalled-enabled": false,
"queue-stalled-minutes": 30, "queue-stalled-minutes": 30,
"ratio-limit": 0.2, "ratio-limit": 1.2,
"ratio-limit-enabled": true, "ratio-limit-enabled": true,
"rename-partial-files": true, "rename-partial-files": true,
"rpc-host-whitelist": "transmission.bb8.fun,transmission", "rpc-host-whitelist": "transmission.bb8.fun,transmission",
@ -51,19 +51,19 @@
"rpc-username": "", "rpc-username": "",
"rpc-whitelist": "127.0.0.1", "rpc-whitelist": "127.0.0.1",
"rpc-whitelist-enabled": false, "rpc-whitelist-enabled": false,
"scrape-paused-torrents-enabled": true, "scrape-paused-torrents-enabled": false,
"script-torrent-done-enabled": false, "script-torrent-done-enabled": false,
"script-torrent-done-filename": "", "script-torrent-done-filename": "",
"seed-queue-enabled": false, "seed-queue-enabled": true,
"seed-queue-size": 10, "seed-queue-size": 50,
"speed-limit-down": 100, "speed-limit-down": 100,
"speed-limit-down-enabled": false, "speed-limit-down-enabled": false,
"speed-limit-up": 50, "speed-limit-up": 50,
"speed-limit-up-enabled": true, "speed-limit-up-enabled": false,
"start-added-torrents": true, "start-added-torrents": true,
"trash-original-torrent-files": false, "trash-original-torrent-files": false,
"umask": 2, "umask": 2,
"upload-slots-per-torrent": 14, "upload-slots-per-torrent": 10,
"utp-enabled": true, "utp-enabled": true,
"watch-dir": "/watch", "watch-dir": "/watch",
"watch-dir-enabled": true "watch-dir-enabled": true

View File

@ -1,3 +1,4 @@
data "docker_network" "bridge" { data "docker_network" "bridge" {
name = "bridge" name = "bridge"
} }

View File

@ -1,47 +1,74 @@
locals {
emby_labels = merge(var.traefik-labels, {
"traefik.frontend.rule" = "Host:emby.in.${var.domain},emby.${var.domain}"
"traefik.frontend.passHostHeader" = "true"
"traefik.port" = 8096
})
}
resource "docker_container" "emby" { resource "docker_container" "emby" {
name = "emby" name = "emby"
image = "${docker_image.emby.latest}" image = docker_image.emby.image_id
# SSD holds both the cache and data
volumes { volumes {
host_path = "/mnt/xwing/config/emby" host_path = "/mnt/zwing/config/emby"
container_path = "/config" container_path = "/config"
} }
# We keep the cache separate
# So the config directory isn't bloated
volumes {
host_path = "/mnt/zwing/cache/emby"
container_path = "/config/cache"
}
# We want backups on the HDD
volumes {
host_path = "/mnt/xwing/backups/config/emby"
container_path = "/backups"
}
# And mount the media as well
volumes { volumes {
host_path = "/mnt/xwing/media" host_path = "/mnt/xwing/media"
container_path = "/media" container_path = "/media"
} }
labels = "${merge( dynamic "labels" {
var.traefik-labels, for_each = local.emby_labels
map( content {
"traefik.frontend.rule", "Host:emby.in.${var.domain},emby.${var.domain}", label = labels.key
"traefik.frontend.passHostHeader", "true", value = labels.value
"traefik.port", 8096, }
))}" }
networks = ["${docker_network.media.id}", "${var.traefik-network-id}"] networks = [docker_network.media.id, var.traefik-network-id]
memory = 2048 memory = 2048
restart = "unless-stopped" restart = "unless-stopped"
destroy_grace_seconds = 10 destroy_grace_seconds = 10
must_run = true must_run = true
# This breaks every time we upgrade the kernel
# or the nvidia driver, and needs a reboot.
gpus = "all"
# Running as lounge:tatooine # Running as lounge:tatooine
env = [ env = [
"APP_USER=lounge", "UID=1004",
"APP_UID=1004", "GID=1003",
"APP_GID=1003", "GIDLIST=1003"
"APP_CONFIG=/mnt/xwing/config",
"TZ=Asia/Kolkata",
] ]
} }
resource "docker_image" "emby" { resource "docker_image" "emby" {
name = "${data.docker_registry_image.emby.name}" name = data.docker_registry_image.emby.name
pull_triggers = ["${data.docker_registry_image.emby.sha256_digest}"] pull_triggers = [data.docker_registry_image.emby.sha256_digest]
} }
data "docker_registry_image" "emby" { data "docker_registry_image" "emby" {
name = "emby/embyserver:latest" name = "emby/embyserver:latest"
} }

View File

@ -2,21 +2,23 @@ module "jackett" {
name = "jackett" name = "jackett"
source = "../modules/container" source = "../modules/container"
image = "linuxserver/jackett:latest" image = "linuxserver/jackett:latest"
# TODO FIXME
# networks = [data.docker_network.bridge.id]
networks = "${list(data.docker_network.bridge.id)}" web = {
web {
expose = true expose = true
port = 9117 port = 9117
host = "jackett.${var.domain}" host = "jackett.${var.domain}"
} }
volumes = [{ volumes = [
host_path = "/mnt/xwing/config/jackett" {
container_path = "/config" host_path = "/mnt/xwing/config/jackett"
}] container_path = "/config"
},
]
resource { resource = {
memory = "256" memory = "256"
memory_swap = "512" memory_swap = "512"
} }
@ -27,3 +29,4 @@ module "jackett" {
"TZ=Asia/Kolkata", "TZ=Asia/Kolkata",
] ]
} }

View File

@ -3,19 +3,29 @@ data "docker_registry_image" "lidarr" {
} }
resource "docker_image" "lidarr" { resource "docker_image" "lidarr" {
name = "${data.docker_registry_image.lidarr.name}" name = data.docker_registry_image.lidarr.name
pull_triggers = ["${data.docker_registry_image.lidarr.sha256_digest}"] pull_triggers = [data.docker_registry_image.lidarr.sha256_digest]
}
locals {
lidarr_labels = merge(var.traefik-labels, {
"traefik.port" = 8686
"traefik.frontend.rule" = "Host:lidarr.${var.domain}"
})
} }
resource "docker_container" "lidarr" { resource "docker_container" "lidarr" {
name = "lidarr" name = "lidarr"
image = "${docker_image.lidarr.latest}" image = docker_image.lidarr.image_id
dynamic "labels" {
for_each = local.lidarr_labels
content {
label = labels.key
value = labels.value
}
}
labels = "${merge(
var.traefik-labels, map(
"traefik.port", 8686,
"traefik.frontend.rule","Host:lidarr.${var.domain}"
))}"
memory = 512 memory = 512
restart = "unless-stopped" restart = "unless-stopped"
@ -43,5 +53,6 @@ resource "docker_container" "lidarr" {
"TZ=Asia/Kolkata", "TZ=Asia/Kolkata",
] ]
networks = ["${docker_network.media.id}", "${var.traefik-network-id}"] networks = [docker_network.media.id, var.traefik-network-id]
} }

View File

@ -5,41 +5,46 @@ module "navidrome" {
user = 1004 user = 1004
resource { resource = {
memory = "1024" memory = "1024"
memory_swap = "1024" memory_swap = "1024"
} }
web { web = {
port = 4533 port = 4533
host = "music.bb8.fun" host = "music.bb8.fun"
expose = true expose = true
} }
env = [ env = [
"ND_SCANINTERVAL=1h", "ND_SCANINTERVAL=6h",
"ND_LOGLEVEL=info", "ND_LOGLEVEL=info",
"ND_SESSIONTIMEOUT=300h", "ND_SESSIONTIMEOUT=300h",
"ND_BASEURL=", "ND_BASEURL=",
"ND_AUTOIMPORTPLAYLISTS=false", "ND_AUTOIMPORTPLAYLISTS=false",
# "ND_UIWELCOMEMESSAGE=Welcome to Scarif Music Archives",
"ND_LASTFM_APIKEY=${var.lastfm_api_key}", "ND_LASTFM_APIKEY=${var.lastfm_api_key}",
"ND_LASTFM_SECRET=${var.lastfm_secret}", "ND_LASTFM_SECRET=${var.lastfm_secret}",
"ND_SPOTIFY_ID=${var.spotify_id}", "ND_SPOTIFY_ID=${var.spotify_id}",
"ND_SPOTIFY_SECRET=${var.spotify_secret}" "ND_SPOTIFY_SECRET=${var.spotify_secret}",
] ]
networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" # TODO FIXME
# networks = [docker_network.media.id, data.docker_network.bridge.id]
# Keep cache and data config so we can do easier backups
volumes = [ volumes = [
{ {
host_path = "/mnt/xwing/data/navidrome" host_path = "/mnt/zwing/config/navidrome"
container_path = "/data" container_path = "/data"
},{
host_path = "/mnt/zwing/cache/navidrome"
container_path = "/data/cache"
}, },
{ {
host_path = "/mnt/xwing/media/Music" host_path = "/mnt/xwing/media/Music"
container_path = "/music" container_path = "/music"
read_only = true read_only = true
} },
] ]
} }

View File

@ -3,7 +3,7 @@ resource "docker_network" "media" {
driver = "bridge" driver = "bridge"
ipam_config { ipam_config {
subnet = "172.18.0.0/16" subnet = "172.18.0.0/24"
gateway = "172.18.0.1" gateway = "172.18.0.1"
} }
} }

View File

@ -1,7 +1,8 @@
output "names-transmission" { output "names-transmission" {
value = "${docker_container.transmission.name}" value = docker_container.transmission.name
} }
output "names-emby" { output "names-emby" {
value = "${docker_container.emby.name}" value = docker_container.emby.name
} }

19
media/providers.tf Normal file
View File

@ -0,0 +1,19 @@
terraform {
required_providers {
pass = {
source = "camptocamp/pass"
}
digitalocean = {
source = "digitalocean/digitalocean"
}
postgresql = {
source = "cyrilgdn/postgresql"
}
cloudflare = {
source = "cloudflare/cloudflare"
}
docker = {
source = "kreuzwerker/docker"
}
}
}

33
media/prowlarr.tf Normal file
View File

@ -0,0 +1,33 @@
module "prowlarr" {
name = "prowlarr"
source = "../modules/container"
image = "linuxserver/prowlarr:nightly"
web = {
expose = true
port = 9696
host = "prowlarr.${var.domain}"
auth = true
}
resource = {
memory = 512
memory_swap = 1024
}
volumes = [
{
host_path = "/mnt/xwing/config/prowlarr"
container_path = "/config"
}
]
env = [
"PUID=1004",
"PGID=1003",
"TZ=Asia/Kolkata",
]
networks = [docker_network.media.id, data.docker_network.bridge.id]
}

View File

@ -3,24 +3,29 @@ module "radarr" {
source = "../modules/container" source = "../modules/container"
image = "linuxserver/radarr:latest" image = "linuxserver/radarr:latest"
networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" networks = [docker_network.media.id, data.docker_network.bridge.id]
web { web = {
expose = true expose = true
port = 7878 port = 7878
host = "radarr.${var.domain}" host = "radarr.${var.domain}"
} }
resource { resource = {
memory = 512 memory = 512
memory_swap = 1024 memory_swap = 1024
} }
volumes = [ volumes = [
{ {
host_path = "/mnt/xwing/config/radarr" host_path = "/mnt/zwing/config/radarr"
container_path = "/config" container_path = "/config"
}, },
# Backups stay on spinning disks
{
host_path = "/mnt/xwing/backups/config/sonarr"
container_path = "/config/Backups"
},
{ {
host_path = "/mnt/xwing/media/DL" host_path = "/mnt/xwing/media/DL"
container_path = "/downloads" container_path = "/downloads"
@ -37,3 +42,4 @@ module "radarr" {
"TZ=Asia/Kolkata", "TZ=Asia/Kolkata",
] ]
} }

View File

@ -3,13 +3,13 @@ module "requestrr" {
source = "../modules/container" source = "../modules/container"
image = "darkalfx/requestrr:latest" image = "darkalfx/requestrr:latest"
web { web = {
expose = true expose = true
port = 4545 port = 4545
host = "requestrr.${var.domain}" host = "requestrr.${var.domain}"
} }
resource { resource = {
memory = 256 memory = 256
memory_swap = 256 memory_swap = 256
} }
@ -18,8 +18,9 @@ module "requestrr" {
{ {
host_path = "/mnt/xwing/config/requestrr" host_path = "/mnt/xwing/config/requestrr"
container_path = "/root/config" container_path = "/root/config"
} },
] ]
networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" networks = [docker_network.media.id, data.docker_network.bridge.id]
} }

View File

@ -3,22 +3,27 @@ module "sonarr-container" {
source = "../modules/container" source = "../modules/container"
image = "linuxserver/sonarr:latest" image = "linuxserver/sonarr:latest"
web { web = {
expose = true expose = true
port = 8989 port = 8989
host = "sonarr.${var.domain}" host = "sonarr.${var.domain}"
} }
resource { resource = {
memory = 512 memory = 512
memory_swap = 1024 memory_swap = 1024
} }
volumes = [ volumes = [
{ {
host_path = "/mnt/xwing/config/sonarr" host_path = "/mnt/zwing/config/sonarr"
container_path = "/config" container_path = "/config"
}, },
# Backups stay on spinning disks
{
host_path = "/mnt/xwing/backups/config/sonarr"
container_path = "/config/Backups"
},
{ {
host_path = "/mnt/xwing/media/DL" host_path = "/mnt/xwing/media/DL"
container_path = "/downloads" container_path = "/downloads"
@ -35,5 +40,6 @@ module "sonarr-container" {
"TZ=Asia/Kolkata", "TZ=Asia/Kolkata",
] ]
networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" networks = [docker_network.media.id, data.docker_network.bridge.id]
} }

View File

@ -1,18 +1,26 @@
locals {
transmission_labels = merge(var.traefik-labels, {
"traefik.frontend.auth.basic" = var.basic_auth
"traefik.port" = 9091
})
}
resource "docker_container" "transmission" { resource "docker_container" "transmission" {
name = "transmission" name = "transmission"
image = "${docker_image.transmission.latest}" image = docker_image.transmission.image_id
labels = "${merge( dynamic "labels" {
var.traefik-labels, for_each = local.transmission_labels
map( content {
"traefik.frontend.auth.basic", "${var.basic_auth}", label = labels.key
"traefik.port", 9091, value = labels.value
))}" }
}
ports { ports {
internal = 51413 internal = 51413
external = 51413 external = 51413
ip = "${var.ips["eth0"]}" ip = var.ips["eth0"]
protocol = "udp" protocol = "udp"
} }
@ -26,13 +34,18 @@ resource "docker_container" "transmission" {
container_path = "/downloads" container_path = "/downloads"
} }
volumes {
host_path = "/mnt/xwing/media/Music/Audiobooks"
container_path = "/audiobooks"
}
volumes { volumes {
host_path = "/mnt/xwing/data/watch/transmission" host_path = "/mnt/xwing/data/watch/transmission"
container_path = "/watch" container_path = "/watch"
} }
upload { upload {
content = "${file("${path.module}/conf/transmission.json")}" content = file("${path.module}/conf/transmission.json")
file = "/config/settings.json" file = "/config/settings.json"
} }
@ -42,7 +55,7 @@ resource "docker_container" "transmission" {
"TZ=Asia/Kolkata", "TZ=Asia/Kolkata",
] ]
networks = ["${docker_network.media.id}", "${var.traefik-network-id}"] networks = [docker_network.media.id, var.traefik-network-id]
memory = 1024 memory = 1024
restart = "unless-stopped" restart = "unless-stopped"
@ -51,10 +64,11 @@ resource "docker_container" "transmission" {
} }
resource "docker_image" "transmission" { resource "docker_image" "transmission" {
name = "${data.docker_registry_image.transmission.name}" name = data.docker_registry_image.transmission.name
pull_triggers = ["${data.docker_registry_image.transmission.sha256_digest}"] pull_triggers = [data.docker_registry_image.transmission.sha256_digest]
} }
data "docker_registry_image" "transmission" { data "docker_registry_image" "transmission" {
name = "linuxserver/transmission:latest" name = "linuxserver/transmission:latest"
} }

View File

@ -1,11 +1,11 @@
variable "domain" { variable "domain" {
type = "string" type = string
} }
# variable "airsonic-smtp-password" {} # variable "airsonic-smtp-password" {}
variable "traefik-labels" { variable "traefik-labels" {
type = "map" type = map(string)
} }
// TODO: Remove duplication // TODO: Remove duplication
@ -14,23 +14,29 @@ variable "basic_auth" {
} }
variable "ips" { variable "ips" {
type = "map" type = map(string)
}
variable "traefik-network-id" {
} }
variable "traefik-network-id" {}
variable "lastfm_api_key" { variable "lastfm_api_key" {
description = "Navidrome Configuration for lastfm_api_key" description = "Navidrome Configuration for lastfm_api_key"
type = "string" type = string
} }
variable "lastfm_secret" { variable "lastfm_secret" {
description = "Navidrome Configuration for lastfm_secret" description = "Navidrome Configuration for lastfm_secret"
type = "string" type = string
} }
variable "spotify_id" { variable "spotify_id" {
description = "Navidrome Configuration for spotify_id" description = "Navidrome Configuration for spotify_id"
type = "string" type = string
} }
variable "spotify_secret" { variable "spotify_secret" {
description = "Navidrome Configuration for spotify_secret" description = "Navidrome Configuration for spotify_secret"
type = "string" type = string
} }

View File

@ -1,28 +1,30 @@
module "miniflux-container" { module "miniflux-container" {
name = "miniflux" name = "miniflux"
source = "modules/container" source = "./modules/container"
image = "miniflux/miniflux:2.0.28" image = "miniflux/miniflux:2.0.50"
web { web = {
expose = true expose = true
port = 8080 port = 8080
host = "rss.captnemo.in" host = "rss.captnemo.in"
} }
networks = "${list( networks = ["bridge", "postgres"]
data.docker_network.bridge.id,
module.docker.traefik-network-id,
module.db.postgres-network-id
)}"
env = [ env = [
"DATABASE_URL=postgres://miniflux:${data.pass_password.miniflux-db-password.password}@postgres/miniflux?sslmode=disable", "DATABASE_URL=postgres://miniflux:${data.pass_password.miniflux-db-password.password}@postgres/miniflux?sslmode=disable",
"RUN_MIGRATIONS=1", "RUN_MIGRATIONS=1",
] ]
resource = {
memory = 512
memory_swap = 1024
}
} }
module "miniflux-db" { module "miniflux-db" {
source = "modules/postgres" source = "./modules/postgres"
name = "miniflux" name = "miniflux"
password = "${data.pass_password.miniflux-db-password.password}" password = data.pass_password.miniflux-db-password.password
} }

View File

@ -0,0 +1,9 @@
data "docker_registry_image" "image" {
name = var.image
}
resource "docker_image" "image" {
name = var.image
pull_triggers = [data.docker_registry_image.image.sha256_digest]
keep_locally = var.keep_image
}

View File

@ -1,36 +1,49 @@
locals { locals {
default_labels { default_labels = {
"managed.by" = "nebula" "managed.by" = "nebula"
} }
web { web = {
"traefik.port" = "${lookup(var.web, "port", "80")}" "traefik.port" = var.web.port != null ? var.web.port : 80
"traefik.frontend.rule" = "Host:${lookup(var.web, "host", "example.invalid")}" "traefik.frontend.rule" = var.web.host != null ? "Host:${var.web.host}" : "Host:example.invalid"
"traefik.protocol" = "${lookup(var.web, "protocol", "http")}" "traefik.protocol" = var.web.protocol != null ? var.web.protocol : "http"
} }
resource { traefik_common_labels = {
memory = "${lookup(var.resource, "memory", 64)}"
memory_swap = "${lookup(var.resource, "memory_swap", 128)}"
}
traefik_common_labels {
"traefik.enable" = "true" "traefik.enable" = "true"
// HSTS // HSTS
"traefik.frontend.headers.SSLTemporaryRedirect" = "true" "traefik.frontend.headers.SSLTemporaryRedirect" = "true"
"traefik.frontend.headers.STSSeconds" = "2592000" "traefik.frontend.headers.STSSeconds" = "2592000"
"traefik.frontend.headers.STSIncludeSubdomains" = "false" "traefik.frontend.headers.STSIncludeSubdomains" = "false"
// X-Powered-By, Server headers // X-Powered-By, Server headers
"traefik.frontend.headers.customResponseHeaders" = "${var.xpoweredby}" "traefik.frontend.headers.customResponseHeaders" = var.xpoweredby
"traefik.frontend.headers.contentTypeNosniff" = "true" "traefik.frontend.headers.contentTypeNosniff" = "true"
"traefik.frontend.headers.browserXSSFilter" = "true" "traefik.frontend.headers.browserXSSFilter" = "true"
"traefik.docker.network" = "traefik"
"traefik.docker.network" = "traefik"
} }
traefik_auth_labels { # if var.web.auth == true
"traefik.frontend.auth.basic" = "${var.auth_header}" traefik_auth_labels = {
"traefik.frontend.auth.basic" = var.auth_header
} }
resource = {
memory = lookup(var.resource, "memory", 64)
memory_swap = lookup(var.resource, "memory_swap", 128)
}
labels = merge(
# Default labels are applied to every container
local.default_labels,
# Add the common traefik labels
var.web.expose ? local.traefik_common_labels : null,
# Apply the overwritten web labels only if the container is exposed
var.web.expose ? local.web : null,
# And finally a label for Basic Authentication if the service wants it
var.web.auth != null ? (var.web.auth ? local.traefik_auth_labels : null) : null,
var.labels,
)
networks = concat(var.networks, var.web.expose ? ["traefik"] : [])
} }

View File

@ -1,125 +1,86 @@
data "docker_registry_image" "image" {
name = "${var.image}"
}
resource "docker_image" "image" {
name = "${var.image}"
pull_triggers = ["${data.docker_registry_image.image.sha256_digest}"]
keep_locally = "${var.keep_image}"
}
data "docker_network" "traefik" {
name = "traefik"
}
resource "docker_container" "container" { resource "docker_container" "container" {
name = "${var.name}" name = var.name
image = "${docker_image.image.latest}" image = docker_image.image.image_id
ports = "${var.ports}"
restart = "${var.restart}"
env = ["${var.env}"]
command = "${var.command}"
entrypoint = "${var.entrypoint}"
user = "${var.user}"
network_mode = "${var.network_mode}" dynamic "ports" {
for_each = var.ports
content {
external = ports.value.external
internal = ports.value.internal
ip = ports.value.ip
protocol = lookup(ports.value, "protocol", "tcp")
}
}
restart = var.restart
env = var.env
command = var.command
entrypoint = var.entrypoint
user = var.user
capabilities = ["${var.capabilities}"] privileged = var.privileged
// Only attach the traefik network if network_mode = var.network_mode
// service is exposed to the web
networks = ["${concat(var.networks,compact(split(",",lookup(var.web, "expose", "false") == "false" ? "" :"${data.docker_network.traefik.id}")))}"]
networks_advanced = ["${var.networks_advanced}"] gpus = var.gpu ? "all" : ""
memory = "${local.resource["memory"]}" dynamic "capabilities" {
memory_swap = "${local.resource["memory_swap"]}" for_each = [var.capabilities]
content {
add = lookup(capabilities.value, "add", [])
drop = lookup(capabilities.value, "drop", [])
}
}
volumes = ["${var.volumes}"] dynamic "networks_advanced" {
devices = ["${var.devices}"] for_each = local.networks
content {
name = networks_advanced.value
}
}
upload = ["${var.uploads}"] memory = local.resource["memory"]
memory_swap = local.resource["memory_swap"]
# Look at this monstrosity dynamic "volumes" {
# And then https://github.com/hashicorp/terraform/issues/12453#issuecomment-365569618 for_each = var.volumes
# for why this is needed content {
container_path = lookup(volumes.value, "container_path", null)
from_container = lookup(volumes.value, "from_container", null)
host_path = lookup(volumes.value, "host_path", null)
read_only = lookup(volumes.value, "read_only", null)
volume_name = lookup(volumes.value, "volume_name", null)
}
}
labels = "${merge(local.default_labels, dynamic "devices" {
zipmap( for_each = var.devices
concat( content {
keys(local.default_labels), host_path = devices.value["host_path"]
split("~", container_path = devices.value["container_path"]
lookup(var.web, "expose", "false") == "false" ? permissions = devices.value["permissions"]
"" : }
join("~", keys(local.traefik_common_labels)) }
)
),
concat(
values(local.default_labels),
split("~",
lookup(var.web, "expose", "false") == "false" ?
"" :
join("~", values(local.traefik_common_labels))
)
)
),
zipmap(
concat(
keys(local.default_labels),
split("~",
lookup(var.web, "expose", "false") == "false" ?
"" :
join("~", keys(local.web))
)
),
concat(
values(local.default_labels),
split("~",
lookup(var.web, "expose", "false") == "false" ?
"" :
join("~", values(local.web))
)
)
),
dynamic "upload" {
for_each = var.uploads
content {
file = lookup(upload.value, "file", null)
content = lookup(upload.value, "content", null)
content_base64 = lookup(upload.value, "content_base64", null)
executable = lookup(upload.value, "executable", null)
source = lookup(upload.value, "source", null)
source_hash = lookup(upload.value, "source_hash", null)
}
}
zipmap( dynamic "labels" {
concat( for_each = local.labels
keys(local.default_labels), content {
split("~", label = labels.key
lookup(var.web, "expose", "false") == "false" ? value = labels.value
"" : }
join("~", keys(local.traefik_common_labels)) }
)
), destroy_grace_seconds = var.destroy_grace_seconds
concat( must_run = var.must_run
values(local.default_labels),
split("~",
lookup(var.web, "expose", "false") == "false" ?
"" :
join("~", values(local.traefik_common_labels))
)
)
),
zipmap(
concat(
keys(local.default_labels),
split("~",
lookup(var.web, "auth", "false") == "false" ?
"" :
join("~", keys(local.traefik_auth_labels))
)
),
concat(
values(local.default_labels),
split("~",
lookup(var.web, "auth", "false") == "false" ?
"" :
join("~", values(local.traefik_auth_labels))
)
)
)
)}"
destroy_grace_seconds = "${var.destroy_grace_seconds}"
must_run = "${var.must_run}"
} }

View File

@ -0,0 +1,7 @@
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
}
}
}

View File

@ -8,19 +8,13 @@ variable "name" {
variable "ports" { variable "ports" {
description = "list of port mappings" description = "list of port mappings"
type = "list" type = list(map(string))
default = []
}
variable "networks_advanced" {
description = "list of networks_advanced"
type = "list"
default = [] default = []
} }
variable "networks" { variable "networks" {
description = "list of networks" description = "list of names of networks to attach to"
type = "list" type = list(string)
default = [] default = []
} }
@ -32,7 +26,7 @@ variable "restart" {
variable "must_run" { variable "must_run" {
description = "If true, then the Docker container will be kept running. " description = "If true, then the Docker container will be kept running. "
default = "true" default = "true"
type = "string" type = string
} }
variable "user" { variable "user" {
@ -43,7 +37,7 @@ variable "user" {
variable "destroy_grace_seconds" { variable "destroy_grace_seconds" {
description = "Container will be destroyed after n seconds or on successful stop." description = "Container will be destroyed after n seconds or on successful stop."
default = 10 default = 10
type = "string" type = string
} }
variable "command" { variable "command" {
@ -63,7 +57,7 @@ variable "env" {
variable "labels" { variable "labels" {
description = "labels" description = "labels"
default = {} default = {}
} }
variable "xpoweredby" { variable "xpoweredby" {
@ -72,10 +66,20 @@ variable "xpoweredby" {
variable "web" { variable "web" {
description = "Web Configuration" description = "Web Configuration"
type = object({
expose = bool
auth = optional(bool)
port = optional(number)
host = optional(string)
protocol = optional(string)
})
default = { default = {
expose = "false" expose = false
auth = "false" auth = false
port = 80
host = ""
protocol = "http"
} }
} }
@ -95,20 +99,28 @@ variable "resource" {
variable "volumes" { variable "volumes" {
description = "volumes" description = "volumes"
type = "list" default = {}
default = [] }
variable "privileged" {
description = " If true, the container runs in privileged mode."
default = false
} }
variable "capabilities" { variable "capabilities" {
description = "capabilities" description = "capabilities"
type = "list"
default = [] default = {
add = []
drop = []
}
} }
variable "devices" { variable "devices" {
description = "devices" description = "list of devices"
type = "list" type = list(map(string))
default = []
default = []
} }
variable "keep_image" { variable "keep_image" {
@ -117,5 +129,20 @@ variable "keep_image" {
} }
variable "uploads" { variable "uploads" {
description = "Files to Upload"
type = list(object({
file = string
content = optional(string)
content_base64 = optional(string)
executable = optional(bool)
source = optional(string)
source_hash = optional(string)
}))
default = [] default = []
} }
variable "gpu" {
type = bool
default = false
}

View File

@ -3,14 +3,15 @@ variable "image" {
} }
data "docker_registry_image" "image" { data "docker_registry_image" "image" {
name = "${var.image}" name = var.image
} }
resource "docker_image" "image" { resource "docker_image" "image" {
name = "${data.docker_registry_image.image.name}" name = data.docker_registry_image.image.name
pull_triggers = ["${data.docker_registry_image.image.sha256_digest}"] pull_triggers = [data.docker_registry_image.image.sha256_digest]
} }
output "image" { output "image" {
value = "${docker_image.image.latest}" value = docker_image.image.image_id
} }

View File

@ -1,6 +1,6 @@
resource "docker_container" "redis" { resource "docker_container" "redis" {
name = "outline-redis" name = "outline-redis"
image = "${docker_image.redis.latest}" image = "${docker_image.redis.image_id}"
volumes { volumes {
host_path = "/mnt/xwing/cache/outline" host_path = "/mnt/xwing/cache/outline"

View File

@ -1,10 +1,11 @@
resource "postgresql_database" "db" { resource "postgresql_database" "db" {
name = "${var.name}" name = var.name
owner = "${var.name}" owner = var.name
} }
resource "postgresql_role" "role" { resource "postgresql_role" "role" {
name = "${var.name}" name = var.name
login = true login = true
password = "${var.password}" password = var.password
} }

View File

@ -0,0 +1,19 @@
terraform {
required_providers {
pass = {
source = "camptocamp/pass"
}
digitalocean = {
source = "digitalocean/digitalocean"
}
postgresql = {
source = "cyrilgdn/postgresql"
}
cloudflare = {
source = "cloudflare/cloudflare"
}
docker = {
source = "kreuzwerker/docker"
}
}
}

View File

@ -1,9 +1,10 @@
variable "name" { variable "name" {
description = "database/role name" description = "database/role name"
type = "string" type = string
} }
variable "password" { variable "password" {
description = "role password" description = "role password"
type = "string" type = string
} }

View File

@ -1,24 +0,0 @@
data "docker_registry_image" "act-exporter" {
name = "captn3m0/prometheus-act-exporter:latest"
}
resource "docker_container" "act-exporter" {
name = "act-exporter"
image = "${docker_image.act-exporter.latest}"
entrypoint = ["/usr/local/bin/node", "server.js"]
networks_advanced {
name = "monitoring"
aliases = ["act-exporter", "act-exporter.docker"]
}
// So it can talk to ACT
networks_advanced {
name = "bridge"
}
restart = "unless-stopped"
destroy_grace_seconds = 10
must_run = true
}

View File

@ -1,9 +1,9 @@
module "cadvisor" { module "cadvisor" {
source = "../modules/container" source = "../modules/container"
name = "cadvisor" name = "cadvisor"
image = "google/cadvisor:latest" image = "gcr.io/cadvisor/cadvisor"
resource { resource = {
memory = 512 memory = 512
memory_swap = 512 memory_swap = 512
} }
@ -11,6 +11,7 @@ module "cadvisor" {
restart = "unless-stopped" restart = "unless-stopped"
destroy_grace_seconds = 10 destroy_grace_seconds = 10
must_run = true must_run = true
privileged = true
volumes = [ volumes = [
{ {
@ -36,21 +37,16 @@ module "cadvisor" {
{ {
host_path = "/var/run" host_path = "/var/run"
container_path = "/var/run" container_path = "/var/run"
read_only = true
}, },
] ]
networks_advanced = [ networks = ["monitoring"]
{
name = "traefik"
},
{
name = "monitoring"
},
]
web { web = {
expose = true expose = true
port = 8080 port = 8080
auth = true auth = true
} }
} }

View File

@ -34,11 +34,5 @@ scrape_configs:
static_configs: static_configs:
- targets: ["192.168.1.111:1111"] - targets: ["192.168.1.111:1111"]
- job_name: "act"
scrape_interval: 1h
scrape_timeout: 1m
static_configs:
- targets: ["act-exporter:3000"]
rule_files: rule_files:
- "alert.rules" - "alert.rules"

View File

@ -1,3 +1,4 @@
data "docker_registry_image" "prometheus" { data "docker_registry_image" "prometheus" {
name = "prom/prometheus:latest" name = "prom/prometheus:latest"
} }

View File

@ -2,37 +2,35 @@
module "grafana" { module "grafana" {
name = "grafana" name = "grafana"
source = "../modules/container" source = "../modules/container"
image = "grafana/grafana:latest" image = "grafana/grafana-oss:latest"
// grafana:grafana // grafana
user = "984:982" user = "472"
web { resource = {
memory = 512
memory_swap = 512
}
web = {
port = 3000 port = 3000
host = "grafana.${var.domain}" host = "grafana.${var.domain}"
expose = true expose = true
} }
volumes = [{ volumes = [
host_path = "/mnt/xwing/data/grafana"
container_path = "/var/lib/grafana"
}]
networks_advanced = [
{ {
name = "traefik" host_path = "/mnt/xwing/data/grafana"
}, container_path = "/var/lib/grafana"
{
name = "monitoring"
}, },
] ]
networks = ["monitoring"]
env = [ env = [
"GF_SERVER_ROOT_URL=https://grafana.${var.domain}", "GF_SERVER_ROOT_URL=https://grafana.${var.domain}",
"GF_AUTH_ANONYMOUS_ENABLED=true", "GF_AUTH_ANONYMOUS_ENABLED=true",
"GF_AUTH_ANONYMOUS_ORG_NAME=Tatooine", "GF_AUTH_ANONYMOUS_ORG_NAME=Tatooine",
# Keep this disabled unless bringing up a new grafana instance
"GF_SECURITY_ADMIN_PASSWORD=${var.gf-security-admin-password}", "GF_SECURITY_ADMIN_PASSWORD=${var.gf-security-admin-password}",
] ]
@ -40,3 +38,4 @@ module "grafana" {
destroy_grace_seconds = 10 destroy_grace_seconds = 10
must_run = true must_run = true
} }

Some files were not shown because too many files have changed in this diff Show More