Add automatic SSL certificate generation
All checks were successful
Build and Push / build-all (push) Successful in 15s
All checks were successful
Build and Push / build-all (push) Successful in 15s
This commit is contained in:
parent
1220c5101d
commit
38ecb718e7
8 changed files with 92 additions and 31 deletions
|
|
@ -432,9 +432,9 @@ write_files:
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
memory: 512M
|
memory: 3G
|
||||||
reservations:
|
reservations:
|
||||||
memory: 256M
|
memory: 1G
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
forgejo-internal:
|
forgejo-internal:
|
||||||
|
|
@ -471,11 +471,11 @@ write_files:
|
||||||
}
|
}
|
||||||
|
|
||||||
${domain} {
|
${domain} {
|
||||||
# Rate limiting - 100 requests per minute per IP
|
# Rate limiting - 500 requests per minute per IP
|
||||||
rate_limit {
|
rate_limit {
|
||||||
zone forgejo_zone {
|
zone forgejo_zone {
|
||||||
key {remote_host}
|
key {remote_host}
|
||||||
events 100
|
events 500
|
||||||
window 1m
|
window 1m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ services:
|
||||||
JWT_SECRET: ${JWT_SECRET}
|
JWT_SECRET: ${JWT_SECRET}
|
||||||
volumes:
|
volumes:
|
||||||
- uploads:/app/uploads:ro
|
- uploads:/app/uploads:ro
|
||||||
- letsencrypt_data:/etc/letsencrypt:ro
|
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||||||
- certbot_webroot:/var/www/certbot:ro
|
- certbot_webroot:/var/www/certbot:ro
|
||||||
networks:
|
networks:
|
||||||
- frontend
|
- frontend
|
||||||
|
|
@ -203,7 +203,7 @@ services:
|
||||||
image: certbot/certbot:latest
|
image: certbot/certbot:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- letsencrypt_data:/etc/letsencrypt
|
- /etc/letsencrypt:/etc/letsencrypt
|
||||||
- certbot_webroot:/var/www/certbot
|
- certbot_webroot:/var/www/certbot
|
||||||
entrypoint: ["/bin/sh", "-c"]
|
entrypoint: ["/bin/sh", "-c"]
|
||||||
command:
|
command:
|
||||||
|
|
@ -227,5 +227,4 @@ volumes:
|
||||||
redis_data:
|
redis_data:
|
||||||
ome_logs:
|
ome_logs:
|
||||||
uploads:
|
uploads:
|
||||||
letsencrypt_data:
|
|
||||||
certbot_webroot:
|
certbot_webroot:
|
||||||
|
|
|
||||||
|
|
@ -91,17 +91,43 @@ http {
|
||||||
# Default for most uploads (images, stickers)
|
# Default for most uploads (images, stickers)
|
||||||
client_max_body_size 5m;
|
client_max_body_size 5m;
|
||||||
|
|
||||||
|
# ==========================================================================
|
||||||
|
# HTTP Server - Redirect to HTTPS (except ACME challenges)
|
||||||
|
# ==========================================================================
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name localhost;
|
server_name _;
|
||||||
|
|
||||||
# ACME challenge endpoint for Let's Encrypt certificate validation
|
# ACME challenge endpoint for Let's Encrypt certificate validation
|
||||||
# This must come before any access control blocks
|
|
||||||
location /.well-known/acme-challenge/ {
|
location /.well-known/acme-challenge/ {
|
||||||
root /var/www/certbot;
|
root /var/www/certbot;
|
||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Redirect all other HTTP traffic to HTTPS
|
||||||
|
location / {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==========================================================================
|
||||||
|
# HTTPS Server - Main application server
|
||||||
|
# ==========================================================================
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name beeta.realms.pub;
|
||||||
|
|
||||||
|
# SSL certificates (obtained by certbot on host, mounted via docker-compose)
|
||||||
|
ssl_certificate /etc/letsencrypt/live/beeta.realms.pub/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/beeta.realms.pub/privkey.pem;
|
||||||
|
|
||||||
|
# Modern SSL configuration
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
|
||||||
# Site-wide uberban check - blocks banned fingerprints from all endpoints
|
# Site-wide uberban check - blocks banned fingerprints from all endpoints
|
||||||
access_by_lua_block {
|
access_by_lua_block {
|
||||||
-- Skip OPTIONS requests (CORS preflight)
|
-- Skip OPTIONS requests (CORS preflight)
|
||||||
|
|
|
||||||
|
|
@ -38,20 +38,21 @@ locals {
|
||||||
module "app_server" {
|
module "app_server" {
|
||||||
source = "./modules/app_server"
|
source = "./modules/app_server"
|
||||||
|
|
||||||
project_name = var.project_name
|
project_name = var.project_name
|
||||||
environment = var.environment
|
environment = var.environment
|
||||||
region = var.region
|
region = var.region
|
||||||
vpc_uuid = var.vpc_uuid
|
vpc_uuid = var.vpc_uuid
|
||||||
vpc_ip_range = var.vpc_ip_range
|
vpc_ip_range = var.vpc_ip_range
|
||||||
ssh_keys = local.all_ssh_key_ids
|
ssh_keys = local.all_ssh_key_ids
|
||||||
droplet_size = var.app_droplet_size
|
droplet_size = var.app_droplet_size
|
||||||
droplet_image = var.app_droplet_image
|
droplet_image = var.app_droplet_image
|
||||||
ssh_port = var.app_ssh_port
|
ssh_port = var.app_ssh_port
|
||||||
domain = var.app_domain
|
domain = var.app_domain
|
||||||
enable_backups = var.enable_droplet_backups
|
enable_backups = var.enable_droplet_backups
|
||||||
tags = local.common_tags
|
tags = local.common_tags
|
||||||
manage_dns = var.manage_dns
|
manage_dns = var.manage_dns
|
||||||
dns_zone = var.dns_zone
|
dns_zone = var.dns_zone
|
||||||
dns_record_name = var.dns_record_name
|
dns_record_name = var.dns_record_name
|
||||||
forgejo_registry = var.forgejo_registry
|
forgejo_registry = var.forgejo_registry
|
||||||
|
letsencrypt_email = var.letsencrypt_email
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,4 +229,20 @@ runcmd:
|
||||||
- systemctl enable unattended-upgrades
|
- systemctl enable unattended-upgrades
|
||||||
- systemctl start unattended-upgrades
|
- systemctl start unattended-upgrades
|
||||||
|
|
||||||
final_message: "Realms app server ready after $UPTIME seconds. Deploy via Forgejo CI/CD."
|
# Install certbot for SSL certificates
|
||||||
|
- DEBIAN_FRONTEND=noninteractive apt-get -o DPkg::Lock::Timeout=60 install -y certbot
|
||||||
|
|
||||||
|
# Create directories for certbot webroot
|
||||||
|
- mkdir -p /opt/realms/certbot_webroot
|
||||||
|
|
||||||
|
# Obtain initial SSL certificate (standalone mode - no webserver running yet)
|
||||||
|
# This runs before Docker services start, so port 80 is free
|
||||||
|
- |
|
||||||
|
certbot certonly --standalone \
|
||||||
|
--non-interactive \
|
||||||
|
--agree-tos \
|
||||||
|
--email ${letsencrypt_email} \
|
||||||
|
-d ${domain} \
|
||||||
|
|| echo "Certbot failed - certificate may need to be obtained manually after DNS propagates"
|
||||||
|
|
||||||
|
final_message: "Realms app server ready after $UPTIME seconds. SSL cert obtained for ${domain}. Deploy via Forgejo CI/CD."
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,11 @@ resource "digitalocean_droplet" "app" {
|
||||||
ipv6 = true
|
ipv6 = true
|
||||||
|
|
||||||
user_data = templatefile("${path.module}/cloud-init.yaml.tpl", {
|
user_data = templatefile("${path.module}/cloud-init.yaml.tpl", {
|
||||||
ssh_port = var.ssh_port
|
ssh_port = var.ssh_port
|
||||||
vpc_ip_range = var.vpc_ip_range
|
vpc_ip_range = var.vpc_ip_range
|
||||||
domain = var.domain
|
domain = var.domain
|
||||||
forgejo_registry = var.forgejo_registry
|
forgejo_registry = var.forgejo_registry
|
||||||
|
letsencrypt_email = var.letsencrypt_email
|
||||||
})
|
})
|
||||||
|
|
||||||
tags = var.tags
|
tags = var.tags
|
||||||
|
|
|
||||||
|
|
@ -99,3 +99,12 @@ variable "forgejo_registry" {
|
||||||
type = string
|
type = string
|
||||||
default = "qbit.realms.pub"
|
default = "qbit.realms.pub"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SSL Certificate Configuration
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
variable "letsencrypt_email" {
|
||||||
|
description = "Email for Let's Encrypt certificate notifications"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,3 +139,12 @@ variable "forgejo_registry" {
|
||||||
type = string
|
type = string
|
||||||
default = "qbit.realms.pub"
|
default = "qbit.realms.pub"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SSL Certificate Configuration
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
variable "letsencrypt_email" {
|
||||||
|
description = "Email for Let's Encrypt certificate notifications"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue