Skip to content

Instantly share code, notes, and snippets.

@kidGodzilla
Last active April 19, 2024 19:31
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kidGodzilla/aa0b80644b684db8bfd38b411016c888 to your computer and use it in GitHub Desktop.
Save kidGodzilla/aa0b80644b684db8bfd38b411016c888 to your computer and use it in GitHub Desktop.
#!/bin/bash
set -e
######################################################################
# This Bootstrap Script installs Dokku latest on Ubuntu (use LTS or latest)
#
# This script also installs UFW (firewall), some basic Dokku plugins, and
# raises ulimits. Comment out any step you wish to skip.
#
# IMPORTANT: This script also disables password authentication via SSH for
# subsequent logins (a recommended hardening step). Don't forget to add your SSK
# key to your server before logging out!
######################################################################
# See Comments in the related GitHub Gist below for installation instructions
######################################################################
# DOKKU_TAG=v0.32.4
# Ensure we are running as root
check_root() {
if [ "$USER" != "root" ]; then
echo "Permission Denied"
echo "Can only be run by root"
exit
fi
}
# Create a keys file if one does not already exist
create-keys-file() {
mkdir -p ~/.ssh
touch ~/.ssh/authorized_keys
}
# Update apps
apt-get-update() {
sudo apt-get update
}
# Set up automatic updates
automatic-updates() {
# Ubuntu
sudo apt install unattended-upgrades apt-listchanges bsd-mailx -y
# sudo dpkg-reconfigure -plow unattended-upgrades -y
sudo DEBIAN_FRONTEND=noninteractive dpkg-reconfigure --priority=low unattended-upgrades
echo 'Unattended-Upgrade::Automatic-Reboot "true";' >> /etc/apt/apt.conf.d/50unattended-upgrades
sudo unattended-upgrades --dry-run
}
raise-ulimits() {
if ! grep -q "fs.file-max = 65535" "/etc/sysctl.conf"; then
echo "fs.file-max = 65535" >> /etc/sysctl.conf
echo "fs.nr_open = 65535" >> /etc/sysctl.conf
echo "session required pam_limits.so" >> /etc/pam.d/common-session
echo "* soft nproc 65535" >> su
echo "* hard nproc 65535" >> /etc/security/limits.conf
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf
echo "root soft nproc 65535" >> /etc/security/limits.conf
echo "root hard nproc 65535" >> /etc/security/limits.conf
echo "root soft nofile 65535" >> /etc/security/limits.conf
echo "root hard nofile 65535" >> /etc/security/limits.conf
echo "* soft nproc 65535" >> /etc/security/limits.conf
echo "* hard nproc 65535" >> /etc/security/limits.conf
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf
echo "root soft nproc 65535" >> /etc/security/limits.conf
echo "root hard nproc 65535" >> /etc/security/limits.conf
echo "root soft nofile 65535" >> /etc/security/limits.conf
echo "root hard nofile 65535" >> /etc/security/limits.conf
u
ulimit -n 65535
fi
}
# Disable password-based SSH authentication
disable-password-authentication() {
# Disable password authentication
sudo grep -q "ChallengeResponseAuthentication" /etc/ssh/sshd_config && sed -i "/^[^#]*ChallengeResponseAuthentication[[:space:]]yes.*/c\ChallengeResponseAuthentication no" /etc/ssh/sshd_config || echo "ChallengeResponseAuthentication no" >> /etc/ssh/sshd_config
sudo grep -q "^[^#]*PasswordAuthentication" /etc/ssh/sshd_config && sed -i "/^[^#]*PasswordAuthentication[[:space:]]yes/c\PasswordAuthentication no" /etc/ssh/sshd_config || echo "PasswordAuthentication no" >> /etc/ssh/sshd_config
/etc/init.d/ssh reload
}
# Get Dokku if not already installed
install-dokku() {
if ! command -v dokku &> /dev/null
then
wget https://dokku.com/bootstrap.sh;
sudo bash bootstrap.sh
fi
}
# Check that dokku is installed on the server
ensure-dokku() {
if ! command -v dokku &> /dev/null
then
echo "dokku is not installed"
exit
fi
}
# Install UFW
install-firewall() {
apt-get install ufw
ufw enable && sudo ufw allow www && sudo ufw allow https
(yes | sudo ufw allow ssh)
sudo ufw status
}
# Install Fail2Ban
install-fail2ban() {
sudo apt-get install fail2ban -y
if command -v fail2ban &> /dev/null
then
sudo systemctl restart fail2ban
# sudo fail2ban-client status
fi
}
# Make directories for db import/export
make-dirs() {
cd ~
if [ ! -d "$HOME/dumps" ]; then
mkdir dumps
cd dumps
mkdir postgres
mkdir mysql
mkdir redis
mkdir mongo
cd ~
fi
}
# Check if dokku redis plugin is installed and otherwise install it
install-redis() {
if sudo dokku plugin:installed redis; then
echo "=> Redis plugin already installed skipping"
else
echo "=> Installing redis plugin"
sudo dokku plugin:install https://github.com/dokku/dokku-redis.git redis
fi
}
# Check if dokku postgres plugin is installed and otherwise install it
install-postgres() {
if sudo dokku plugin:installed postgres; then
echo "=> Postgres plugin already installed skipping"
else
echo "=> Installing postgres plugin"
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres
fi
}
# Check if dokku MySQL plugin is installed and otherwise install it
install-mysql() {
if sudo dokku plugin:installed mysql; then
echo "=> Postgres plugin already installed skipping"
else
echo "=> Installing mysql plugin"
sudo dokku plugin:install https://github.com/dokku/dokku-mysql.git mysql
fi
}
# Check if dokku mongo plugin is installed and otherwise install it
install-mongo() {
if sudo dokku plugin:installed mongo; then
echo "=> Postgres plugin already installed skipping"
else
echo "=> Installing mongo plugin"
sudo dokku plugin:install https://github.com/dokku/dokku-mongo.git mongo
fi
}
# Check if dokku memcached plugin is installed and otherwise install it
install-memcached() {
if sudo dokku plugin:installed memcached; then
echo "=> Memcached plugin already installed skipping"
else
echo "=> Installing memcached plugin"
sudo dokku plugin:install https://github.com/dokku/dokku-memcached.git memcached
fi
}
# Check if dokku clickhouse plugin is installed and otherwise install it
install-clickhouse() {
if sudo dokku plugin:installed clickhouse; then
echo "=> Clickhouse plugin already installed skipping"
else
echo "=> Installing clickhouse plugin"
sudo dokku plugin:install https://github.com/dokku/dokku-clickhouse.git clickhouse
fi
}
# Install Letsencrypt plugin
install-letsencrypt() {
if [ ! -d "/var/lib/dokku/plugins/available/letsencrypt" ]; then
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
dokku letsencrypt:cron-job --add
fi
}
# Install custom dokku limited users plugin
install-limited-users() {
if [ ! -d "/var/lib/dokku/plugins/available/limited-users" ]; then
sudo dokku plugin:install https://github.com/kidGodzilla/dokku-limited-users.git
fi
}
main() {
check_root
# Get user ip and export to environment variable
DOKKU_SSH_HOST=$(curl ifconfig.co)
SERVER_IP=$(curl ipinfo.io/ip)
# Basics
apt-get-update
install-firewall
# Add access key
create-keys-file
# Hardening
disable-password-authentication
# Install Dokku
install-dokku
make-dirs
# Ensure dokku was installed
ensure-dokku
# dokku databases & plugins
install-redis
install-postgres
install-mysql
install-mongo
install-letsencrypt
# install-limited-users
install-clickhouse
install-memcached
# Additional Configuration
# automatic-updates
# raise-ulimits
# install-fail2ban
}
main
@kidGodzilla
Copy link
Author

kidGodzilla commented Apr 5, 2024

What is Dokku?

Dokku gives you all the tools you need to manage Docker like any other PaaS you've used (Heroku, Vercel, etc). But instead of paying a monthly fee, you own it, and the servers your code run on.

Since it's powered by Docker, it already has plugins to create and manage any database you could imagine, and you can run pretty much anything.

I like to recommend it because it takes less than 5 minutes to learn how it works, and within a few days you'll be an expert. No black box / mystery, it's all open source and very simple.

Installing

  1. Install Ubuntu Latest on a VPS or dedicated server from DigitalOcean, OVH, etc.
  2. SSH into your server.
  3. Add your keys to your server (Password login to SSH will be disabled for security purposes). See "Don't have a Public / Private Keypair?" below for more details.
  4. You might want to sudo su before running the script:
wget https://gist.githubusercontent.com/kidGodzilla/aa0b80644b684db8bfd38b411016c888/raw/242bc8d06585a6ac0d29d3df744a3e3239496af0/server_bootstrap.sh

bash ./server_bootstrap.sh
  1. Add your public key to Dokku (for deploys)
echo "YOUR_PUBLIC_KEY_HERE" | dokku ssh-keys:add admin

Don't have a Public / Private Keypair?

Type the following command to generate a new SSH key pair:

ssh-keygen -t ed25519

You can choose the default options, and you do not need to create a passphrase.

This will generate two files, by default called id_ed25519 and id_ed25519.pub in your ~/.ssh/ directory.

Next, copy this key to your server.

ssh-copy-id ubuntu@1.1.1.1

Before running server_bootstrap.sh, test SSH without a password to ensure you still have access to the server via Public/Private Keypair:

ssh ubuntu@1.1.1.1

@kidGodzilla
Copy link
Author

kidGodzilla commented Apr 5, 2024

Using Dokku

Creating an App (on your Dokku server)

dokku apps:create appname

Add domains to your App (on your Dokku server)

dokku domains:add appname domainname.com domainname2.com sub.domainname.com

Deploying your App

# Add the remote before your first push
git remote add dokku dokku@1.1.1.1:appname

# Use this command every time you push new changes, to deploy
git push dokku main:master

@kidGodzilla
Copy link
Author

kidGodzilla commented Apr 5, 2024

Optional (but recommended)

Install Dokku CLI locally (macOS)

This lets you interact with your Dokku server(s) from the command line of your local repository, so you can view logs, update domains, restart your app, etc. without SSH into your server.

brew install dokku/repo/dokku

Then, for example, inside your project (where you've already added a git remote) you can:

dokku domains:report # list domains
dokku domains:add domainname.com # add a domain
dokku logs # view logs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment