Desbloqueando el Poder del VPS
Una guía a configurar y mantener tu propio servidor
@larrygf
@hiancd
¿Qué es un VPS?
- Exponer Proyectos
- Ahorro en Servicios (VPN, share file,...)
- Mantener Servicios Propios
- Diversión
Para que un VPS?
De que vamos a hablar?
Configuración y Seguridad
Alojar Servicios y utilidades
Alojar Servicios y código propio
Obtener y configurar
- Obtener VPS
- Obtener y Configurar DNS
- Crear Usuario
💰¿Donde lo encuentro?💰
~ 5$
¿Donde obtengo el Dominio?
Inscribir el DNS
Acceso al VPS
ssh root@ejemplito.dev
Instalación
# Programas basicos
apt update
apt install procps apparmor micro gpg htop zsh git \
apt-transport-https ca-certificates curl \
software-properties-common ufw lsb-release \
fail2ban
# Docker (https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository)
mkdir -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg\
-o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Cloudflare DNS
Mejora la latencia y la serguridad
# /etc/resolv.conf
nameserver 1.1.1.1
#/etc/NetworkManager/NetworkManager.conf
[main]
dns=none
Asegurar Acceso Remoto
# /etc/ssh/sshd_config root:root:0600
# Deny root login
PermitRootLogin no
# Deny auth by password
PasswordAuthentication no
# Use linux users
UsePAM yes
# No window forwarding
X11Forwarding no
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
SyslogFacility AUTHPRIV
AuthorizedKeysFile .ssh/authorized_keys
ChallengeResponseAuthentication no
GSSAPIAuthentication yes
GSSAPICleanupCredentials no
Banner /etc/issue.net
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
Subsystem sftp /usr/libexec/openssh/sftp-server
# /etc/fail2ban/jail.conf root:root:0644
[DEFAULT]
# Ban hosts for one hour:
bantime = 1h
# A host is banned if it has generated "maxretry" during the last "findtime":
findtime = 10m
maxretry = 5
# "ignoreip" can be an IP address, a CIDR mask, or a DNS host. Fail2Ban will not
# ban a host which matches an address in this list.
ignoreip = 127.0.0.1/8
# "backend" specifies the backend used to get files modification.
# Options are "pyinotify", "gamin", "polling", "systemd" and "auto".
backend = auto
# "usedns" specifies whether DNS lookups are performed.
# Options are "yes", "warn", "no" (default).
usedns = no
# "destemail" is the destination email for sendmail actions.
destemail = root@localhost
# "mta" is the Mail Transfer Agent used by Fail2Ban to send emails.
# Options are "sendmail" (default), "mail", "qmail", "postfix", "exim", "sendmail-whois",
# "mail-whois", "mail-buffered", "mail-whois-lines", "mail-whois-lines-buffered".
mta = sendmail
# "protocol" by default is set to TCP.
protocol = tcp
# "chain" specifies the iptables chain to which the Fail2Ban rules should be added.
chain = INPUT
# Action to take when banning an IP. See action.d directory for other options
action = %(action_)s
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 3
bantime = 2h
[sshd-ddos]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 6
bantime = 1d
[apache-auth]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 5
bantime = 2h
[apache-badbots]
enabled = true
port = http,https
logpath = %(apache_access_log)s
bantime = 2d
maxretry = 3
Configuración de Usuario
# Add docker group
sudo addgroup docker
USER=ejemplito
# Crear usuario y añadirlo al grupo docker
useradd -m -s /bin/zsh -G docker -G sudo $USER
passwd $USER
mkdir -p /home/$USER/.ssh
# Crear carpetas necesarias
chown -R $USER:$USER /home/$USER/.ssh
chmod 700 /home/$USER/.ssh
DOMAIN=ejemplito.com
USER=ejemplito
ssh-copy-id $USER@$DOMAIN
ssh $USER@$DOMAIN
# (In the remote machine) Test that you can everything is working and then:
sudo reboot
# Ahora de vuelta
echo -e "\nHost ejemplito\n HostName $DOMAIN\n User $USER" >> ~/.ssh/config
sudo systemctl start ufw
sudo systemctl enable ufw
sudo ufw allow OpenSSH
sudo ufw allow 443/tcp
# OpenVPN
sudo ufw allow 1195/udp
Log Rotation
# /etc/logrotate.d/large_logfiles
/var/log/daemon.log
/var/log/syslog
{
rotate 7
daily
size 100M
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
/bin/kill -HUP cat /var/run/syslogd.pid 2> /dev/null 2> /dev/null || true
endscript
}
ZSH Config
https://github.com/ohmyzsh/ohmyzsh.git
https://github.com/romkatv/powerlevel10k.git
https://github.com/zsh-users/zsh-syntax-highlighting.git
https://github.com/zsh-users/zsh-autosuggestions.git
# ~/.zshrc
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
# Initialization code that may require console input (password prompts, [y/n]
# confirmations, etc.) must go above this block; everything else may go below.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH
# Path to your oh-my-zsh installation.
export ZSH="/home/{{ user }}/.oh-my-zsh"
# Set name of the theme to load --- if set to "random", it will
# load a random theme each time oh-my-zsh is loaded, in which case,
# to know which specific one was loaded, run: echo $RANDOM_THEME
# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
ZSH_THEME="powerlevel10k/powerlevel10k"
# Set list of themes to pick from when loading at random
# Setting this variable when ZSH_THEME=random will cause zsh to load
# a theme from this variable instead of looking in $ZSH/themes/
# If set to an empty array, this variable will have no effect.
# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" )
# Uncomment the following line to use case-sensitive completion.
# CASE_SENSITIVE="true"
# Uncomment the following line to use hyphen-insensitive completion.
# Case-sensitive completion must be off. _ and - will be interchangeable.
# HYPHEN_INSENSITIVE="true"
# Uncomment the following line to disable bi-weekly auto-update checks.
# DISABLE_AUTO_UPDATE="true"
# Uncomment the following line to automatically update without prompting.
# DISABLE_UPDATE_PROMPT="true"
# Uncomment the following line to change how often to auto-update (in days).
# export UPDATE_ZSH_DAYS=13
# Uncomment the following line if pasting URLs and other text is messed up.
# DISABLE_MAGIC_FUNCTIONS="true"
# Uncomment the following line to disable colors in ls.
# DISABLE_LS_COLORS="true"
# Uncomment the following line to disable auto-setting terminal title.
# DISABLE_AUTO_TITLE="true"
# Uncomment the following line to enable command auto-correction.
# ENABLE_CORRECTION="true"
# Uncomment the following line to display red dots whilst waiting for completion.
# COMPLETION_WAITING_DOTS="true"
# Uncomment the following line if you want to disable marking untracked files
# under VCS as dirty. This makes repository status check for large repositories
# much, much faster.
# DISABLE_UNTRACKED_FILES_DIRTY="true"
# Uncomment the following line if you want to change the command execution time
# stamp shown in the history command output.
# You can set one of the optional three formats:
# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd"
# or set a custom format using the strftime function format specifications,
# see 'man strftime' for details.
# HIST_STAMPS="mm/dd/yyyy"
# Would you like to use another custom folder than $ZSH/custom?
# ZSH_CUSTOM=/path/to/new-custom-folder
# Which plugins would you like to load?
# Standard plugins can be found in $ZSH/plugins/
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(
git
debian
colored-man-pages
colorize
docker-compose
docker
npm
rsync
sudo
themes
helm
kubectl
zsh-syntax-highlighting
zsh-autosuggestions
)
source $ZSH/oh-my-zsh.sh
# User configuration
# export MANPATH="/usr/local/man:$MANPATH"
# You may need to manually set your language environment
# export LANG=en_US.UTF-8
# Preferred editor for local and remote sessions
# if [[ -n $SSH_CONNECTION ]]; then
# export EDITOR='vim'
# else
# export EDITOR='mvim'
# fi
# Compilation flags
# export ARCHFLAGS="-arch x86_64"
# Set personal aliases, overriding those provided by oh-my-zsh libs,
# plugins, and themes. Aliases can be placed here, though oh-my-zsh
# users are encouraged to define aliases within the ZSH_CUSTOM folder.
# For a full list of active aliases, run alias.
#
# Example aliases
# alias zshconfig="mate ~/.zshrc"
# alias ohmyzsh="mate ~/.oh-my-zsh"
# source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
# source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
# To customize prompt, run p10k configure or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
# source <(kubectl completion zsh)
# source <(helm completion zsh)
echo export ANSIBLE_INVENTORY=/home/$USER/.inventory >> ~/.zshrc
# ~/.inventory
[own]
ejemplito ansible_user=ejemplito
Hosting de servicios
...
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
# /etc/caddy/Caddyfile
ejemplito.com {
respond "Hello HTTPS"
}
# /home/ejemplito/services/portainer/docker-compose.yml
version: "3.3"
services:
portainer:
image: portainer/portainer-ce:latest
restart: unless-stopped
ports:
- "127.0.0.1:9000:9000"
networks:
- services
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
# (optional) These labels are for Homepage automatic integration
labels:
- homepage.group=Services
- homepage.name=Portainer
- homepage.icon=portainer
- homepage.href=https://portainer.ejemplito.com
- homepage.widget.type=portainer
- homepage.widget.env=2
- homepage.widget.url=https://portainer:9443
# - homepage.widget.key=---------------------
volumes:
portainer_data:
networks:
services:
name: services
external: true
# /etc/caddy/Caddyfile
...
import /home/ejemplito/services/*/Caddyfile
# /home/ejemplito/services/portainer/Caddyfile
portainer.nubecita.dev {
reverse_proxy * {
to 127.0.0.1:9000
lb_policy least_conn
lb_try_duration 10s
fail_duration 5s
}
}
# /home/ejemplito/services/homepage/docker-compose
version: "3.3"
services:
homepage:
image: ghcr.io/gethomepage/homepage:latest
ports:
- "127.0.0.1:9001:3000"
networks:
- services
volumes:
- ./config:/app/config
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
networks:
services:
name: services
external: true
# /home/ejemplito/services/homepage/config/docker.yml
my-docker:
socket: /var/run/docker.sock
# /home/ejemplito/services/homepage/config/settings.yml
title: Nubecita Homepage
showStats: true
# /home/ejemplito/services/homepage/config/widgets.yml
- resources:
cpu: true
memory: true
disk: /
Links
Apps Security
ansible-playbook ejemplito.yml
---
- name: Deploy Project to Remote Server and Run Docker-Compose
hosts: own
become: true
vars:
project_src: "../proyectico/"
project_dest: "proyectico/"
caddyfile_content: |
proyectico.ejemplito.com {
reverse_proxy localhost:8601
}
tasks:
- name: Copy project directory to remote server
ansible.builtin.copy:
src: "{{ project_src }}"
dest: "{{ project_dest }}"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0755'
remote_src: no
- name: Run docker-compose up
ansible.builtin.shell: |
cd {{ project_dest }}
docker compose up --build -d
args:
chdir: "{{ project_dest }}"
register: docker_compose_output
- name: Debug docker-compose output
ansible.builtin.debug:
var: docker_compose_output.stdout_lines
- name: Create Caddyfile for reverse proxy
ansible.builtin.copy:
content: "{{ caddyfile_content }}"
dest: "{{ project_dest }}/Caddyfile"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0644'
- name: Restart Caddy
ansible.builtin.systemd:
name: caddy
state: restarted
¿Qué falta?
Desbloqueando el Poder del VPS
Una guía a configurar y mantener tu propio servidor
@larrygf
@hiancd
Desbloqueando el poder del VPS
By Hian Cañizares
Desbloqueando el poder del VPS
- 113