chore: init commit

in worker.../repo/GITFOLDER.zip is the .git folder.
This commit is contained in:
2026-08-11 14:44:09 -04:00
parent 0012380fd3
commit 2854619bc9
782 changed files with 65944 additions and 0 deletions

View File

@@ -0,0 +1,189 @@
#!/usr/bin/env bash
set -euo pipefail
exec > /var/log/bootstrap.log 2>&1
RUBY_VERSION="3.4.4"
APP_USER="ubuntu"
APP_NAME="stocks-in-the-future"
DEPLOY_TO="/home/ubuntu/$APP_NAME"
echo "=== Bootstrap starting: $(date) ==="
# --- System packages ---
apt-get update -qq
apt-get install -y --no-install-recommends \
git curl unzip libssl-dev libreadline-dev zlib1g-dev \
libpq-dev nginx postgresql-client build-essential \
libffi-dev libyaml-dev libgmp-dev \
libvips-dev imagemagick
# --- rbenv for ubuntu user ---
sudo -u "$APP_USER" bash -c '
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
echo "export PATH=\"\$HOME/.rbenv/bin:\$PATH\"" >> ~/.bashrc
echo "eval \"\$(rbenv init -)\"" >> ~/.bashrc
echo "export PATH=\"\$HOME/.rbenv/bin:\$PATH\"" >> ~/.profile
echo "eval \"\$(rbenv init -)\"" >> ~/.profile
'
# Ruby compilation takes ~10-15 minutes
sudo -u "$APP_USER" bash -lc "rbenv install $RUBY_VERSION && rbenv global $RUBY_VERSION"
sudo -u "$APP_USER" bash -lc "gem install bundler --no-document"
# --- Bun ---
sudo -u "$APP_USER" bash -lc 'curl -fsSL https://bun.sh/install | bash'
# --- Capistrano directory structure ---
sudo -u "$APP_USER" bash -c "
mkdir -p $DEPLOY_TO/{releases,shared}
mkdir -p $DEPLOY_TO/shared/{config,log,tmp/pids,tmp/cache,tmp/sockets,storage,public/assets}
"
# --- Shared database.yml (uses DATABASE_URL from /etc/stocks/env) ---
sudo -u "$APP_USER" tee "$DEPLOY_TO/shared/config/database.yml" > /dev/null << 'DBEOF'
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS", 3) %>
staging:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
production:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
DBEOF
# --- master.key (fill in after bootstrap) ---
sudo -u "$APP_USER" bash -c "echo 'FILL_IN_RAILS_MASTER_KEY' > $DEPLOY_TO/shared/config/master.key"
chmod 600 "$DEPLOY_TO/shared/config/master.key"
# --- App secrets env file (fill in real values after bootstrap) ---
mkdir -p /etc/stocks
tee /etc/stocks/env > /dev/null << 'ENVEOF'
RAILS_ENV=production
RAILS_MASTER_KEY=FILL_IN_RAILS_MASTER_KEY
DATABASE_URL=postgres://dbmasteruser:FILL_IN_DB_PASSWORD@FILL_IN_DB_ENDPOINT:5432/stocks_in_the_future_production
STOCKS_IN_THE_FUTURE_DATABASE_PASSWORD=FILL_IN_DB_PASSWORD
ALPHA_VANTAGE_API_KEY=FILL_IN_ALPHA_VANTAGE_KEY
SECRET_KEY_BASE=FILL_IN_RUN_bundle_exec_rails_secret
SOLID_QUEUE_IN_PUMA=1
RAILS_MAX_THREADS=3
RAILS_LOG_LEVEL=info
APP_HOST=app.sifonline.org
MAILER_SENDER=no-reply@sifonline.org
SES_SMTP_ADDRESS=email-smtp.us-east-1.amazonaws.com
SES_SMTP_PORT=587
SES_SMTP_USERNAME=FILL_IN_SES_SMTP_USERNAME
SES_SMTP_PASSWORD=FILL_IN_SES_SMTP_PASSWORD
PUMA_SOCKET=/home/ubuntu/stocks-in-the-future/shared/tmp/sockets/puma.sock
ENVEOF
chown root:ubuntu /etc/stocks/env
chmod 640 /etc/stocks/env
# Source env vars in ubuntu user's shell so Capistrano SSH sessions get them
sudo -u "$APP_USER" bash -c 'echo "" >> ~/.profile && echo "# Load app env vars" >> ~/.profile && echo "set -a; source /etc/stocks/env; set +a" >> ~/.profile'
# --- nginx ---
tee /etc/nginx/sites-available/stocks > /dev/null << 'NGINXEOF'
upstream stocks_puma {
server unix:/home/ubuntu/stocks-in-the-future/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
server_name _;
root /home/ubuntu/stocks-in-the-future/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location /up {
proxy_pass http://stocks_puma;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
access_log off;
}
location / {
proxy_pass http://stocks_puma;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_read_timeout 60;
proxy_connect_timeout 60;
}
error_page 500 502 503 504 /500.html;
keepalive_timeout 10;
}
NGINXEOF
ln -sf /etc/nginx/sites-available/stocks /etc/nginx/sites-enabled/stocks
rm -f /etc/nginx/sites-enabled/default
systemctl enable nginx
# Don't start nginx yet - no socket until first cap deploy
# --- systemd service ---
tee /etc/systemd/system/stocks.service > /dev/null << 'SVCEOF'
[Unit]
Description=Stocks in the Future Rails App
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/stocks-in-the-future/current
Environment="PATH=/home/ubuntu/.rbenv/shims:/home/ubuntu/.rbenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="RBENV_ROOT=/home/ubuntu/.rbenv"
Environment="RBENV_VERSION=3.4.4"
EnvironmentFile=/etc/stocks/env
ExecStart=/home/ubuntu/.rbenv/versions/3.4.4/bin/bundle exec puma -C config/puma.rb
ExecReload=/bin/kill -USR2 $MAINPID
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=stocks
KillMode=mixed
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
SVCEOF
systemctl daemon-reload
systemctl enable stocks
# Don't start - current/ symlink doesn't exist until first cap deploy
# --- sudoers: allow ubuntu to restart the service without a password ---
echo "ubuntu ALL=(ALL) NOPASSWD: /bin/systemctl restart stocks, /bin/systemctl status stocks, /bin/systemctl reload nginx" \
> /etc/sudoers.d/stocks-deploy
chmod 440 /etc/sudoers.d/stocks-deploy
echo "=== Bootstrap complete: $(date) ==="
echo ""
echo "=== NEXT STEPS ==="
echo "1. SSH in and fill in real values in /etc/stocks/env:"
echo " sudo nano /etc/stocks/env"
echo " - RAILS_MASTER_KEY: contents of config/master.key in the repo"
echo " - DATABASE_URL: use db endpoint from: cd terraform/production && terraform output db_endpoint"
echo " - STOCKS_IN_THE_FUTURE_DATABASE_PASSWORD: the db master password"
echo " - ALPHA_VANTAGE_API_KEY: your API key"
echo " - SECRET_KEY_BASE: run 'bundle exec rails secret' locally to generate"
echo " - SES_SMTP_USERNAME / SES_SMTP_PASSWORD: SES SMTP credentials for us-east-1"
echo "2. Also update shared/config/master.key:"
echo " echo 'your-master-key' > ~/stocks-in-the-future/shared/config/master.key"
echo "3. Run first deploy from your local machine:"
echo " PRODUCTION_SERVER_IP=54.224.224.77 bundle exec cap production deploy"
echo "4. Start nginx:"
echo " sudo systemctl start nginx"

View File

@@ -0,0 +1,93 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
# Recommended: store state in S3 to share with teammates
# backend "s3" {
# bucket = "your-tf-state-bucket"
# key = "stocks-production/terraform.tfstate"
# region = "us-east-1"
# }
}
provider "aws" {
region = var.aws_region
}
resource "aws_lightsail_instance" "production" {
name = "production_web"
availability_zone = "${var.aws_region}a"
blueprint_id = "ubuntu_24_04"
bundle_id = var.instance_bundle_id
key_pair_name = var.lightsail_ssh_key_name
tags = {
Environment = "production"
App = "stocks-in-the-future"
ManagedBy = "terraform"
}
}
resource "aws_lightsail_instance_public_ports" "production" {
instance_name = aws_lightsail_instance.production.name
port_info {
from_port = 22
to_port = 22
protocol = "tcp"
}
port_info {
from_port = 80
to_port = 80
protocol = "tcp"
}
}
resource "aws_lightsail_database" "production" {
relational_database_name = "production-db"
availability_zone = "${var.aws_region}a"
master_database_name = "stocks_in_the_future_production"
master_username = "dbmasteruser"
master_password = var.db_master_password
blueprint_id = "postgres_16"
bundle_id = var.db_bundle_id
skip_final_snapshot = false # always keep a snapshot when destroying production
tags = {
Environment = "production"
App = "stocks-in-the-future"
ManagedBy = "terraform"
}
}
resource "aws_lightsail_lb" "production" {
name = "stocks-production-lb"
instance_port = 80
health_check_path = "/up"
tags = {
Environment = "production"
App = "stocks-in-the-future"
ManagedBy = "terraform"
}
}
resource "aws_lightsail_lb_attachment" "production" {
lb_name = aws_lightsail_lb.production.name
instance_name = aws_lightsail_instance.production.name
}
resource "aws_lightsail_lb_certificate" "production" {
name = "production-ssl"
lb_name = aws_lightsail_lb.production.name
domain_name = "app.sifonline.org"
}
resource "aws_lightsail_lb_certificate_attachment" "production" {
lb_name = aws_lightsail_lb.production.name
certificate_name = aws_lightsail_lb_certificate.production.name
}

View File

@@ -0,0 +1,23 @@
output "instance_public_ip" {
value = aws_lightsail_instance.production.public_ip_address
description = "Set PRODUCTION_SERVER_IP in config/deploy/production.rb to this value"
}
output "db_endpoint" {
value = aws_lightsail_database.production.master_endpoint_address
description = "Database endpoint for DATABASE_URL in /etc/stocks/env"
}
output "db_port" {
value = aws_lightsail_database.production.master_endpoint_port
}
output "lb_dns" {
value = aws_lightsail_lb.production.dns_name
description = "Load balancer DNS name - point your production DNS CNAME here"
}
output "lb_certificate_validation_records" {
value = aws_lightsail_lb_certificate.production.domain_validation_records
description = "Create these DNS records if the production load balancer certificate needs validation"
}

View File

@@ -0,0 +1,10 @@
# Copy this to terraform.tfvars and fill in real values
# terraform.tfvars is gitignored - never commit it
aws_region = "us-east-1"
lightsail_ssh_key_name = "LightsailDefaultKey-us-east-1"
instance_bundle_id = "small_3_0" # check AWS console for actual production bundle
db_bundle_id = "micro_2_0" # check AWS console for actual production DB bundle
db_master_password = "your-production-db-password-here"
rails_master_key = "your-master-key-here"
alpha_vantage_api_key = "your-api-key-here"

View File

@@ -0,0 +1,38 @@
variable "aws_region" {
default = "us-east-1"
}
variable "lightsail_ssh_key_name" {
description = "Name of the existing Lightsail SSH key pair"
type = string
}
variable "instance_bundle_id" {
description = "Lightsail instance bundle (size). Check AWS console for the existing production bundle ID."
type = string
default = "small_3_0"
}
variable "db_bundle_id" {
description = "Lightsail managed database bundle ID. Check AWS console for the existing production DB bundle ID."
type = string
default = "micro_2_0"
}
variable "db_master_password" {
description = "Master password for the production PostgreSQL database"
type = string
sensitive = true
}
variable "rails_master_key" {
description = "Rails master key (contents of config/master.key)"
type = string
sensitive = true
}
variable "alpha_vantage_api_key" {
description = "Alpha Vantage API key"
type = string
sensitive = true
}