tomcon.net is my first ever website. I have never self-hosted a external service like this before. Getting to this point where text is rendering on your screen took a decent amount of learning and trial+error. Before this I was vaugely familiar with some computer networking essentials like internal/external ips and forwarding port numbers. I have been using linux mint as a daily driver for a few years so I know the basics of UNIX file structure and how to work a terminal.
This site is hosted on a thinkpad t440s running linux mint 22.1 cinnamon. The laptop was a spare I had lying around. I finally put it to good use.
I think you should start with buying a domain name as your first step. Its useful to know going into this what your domain name is going to be. Theres many providers that are suggested. I choose epik.com as a domain name provider but you can go with cloudflare, namecheap, and many others.
I now pay 15$/yr for the privlege of renting a human readable name certified by a domain authority that gets tie to my networks external IP address. Its unfortunate I cant self-host the domain registry process too. For now im stuck with renting a name from an authority and using their web services to configure things. Its a necessary evil you gotta do to have a website.
Note that other network protocols for sharing information like I2P and TOR do away with the need for a domain name system I believe.
when you find out your external ip with whatsmyip.com, go into your domain name providers web interface and find 'DNS Host Records', Here make sure your domain and subdomains (with the A, AAAA records) point to your servers external IP. Do the same process for all subdomains you want to create, they all take the exact same pointed ip number configuration.
This is the core step of setting up my website. A good operating system like Linux Mint provides an out-of-the-box beginner friendly ecosystem thats easy to install, bulletproof stability, and good community support with over a decade of fourm activity and a very active IRC to fall back on. Note that other operating systems are purpose built as hardened and secured headless server OS. At some point I may feel the need to switch to one.
Apache is a simple web page server. A client request connection to apache, then apache sends html page information to a recieving client on an open port.
sudo lsof -i :80
To use a terminal to connect to the webpage and pull the index HTML file:
curl -I http://localhost
sudo nano /etc/hosts
10.0.0.XX yourdomain.com www.yourdomain.com
Another potential option especially if troubleshooting and the domain name isn't working for whatever reason is to use direct local ip and port numbers. enter into your browser `http:10.0.0.xx` `http:10.0.0.xx:8080`, or http:localhost:8080 into the address bar. You can try undoing port change from 8080 back to 80 and connecting without defining port after restart (your web browser automatically request http on 80 and https on 443). You can also try allowing 8080 through the firewall if its already set up. The goal is just to see if apache is running/serving the default page and if you can connect locally.
Located in '/etc/apache2/ports.conf'
# If you just change the port or add more ports here, you will likely also # have to change the VirtualHost statement in # /etc/apache2/sites-enabled/000-default.conf Listen 8080 <IfModule ssl_module> # Listen 443 </IfModule> <IfModule mod_gnutls.c> # Listen 443 </IfModule>
Make sure apache is running and you can connect locally. If so, its time to move on to exposing the service to external client connections. Its heavily recommended that you follow the next steps for security hardening+reverse proxy with caddy. It is entirely possible for you to just serve regular unencrypted http at this point though. Port forward 80/TCP of your servers local ip in the gateway/router settings and point the domain name at your networks external IP address. Adjust security headers through apache. External clients should be able to recieve html pages using your domain name through http but they'll recieve warnings every time they connect and your SEO will hurt. Its better for everyone involved to set up a way to handle SSL/TLS certificates.
caddy serves two important roles along with apache.
A reverse proxy is the solution to two problems at once. It handles pairing a external sub-domain with a specific local ip. And if some of these external services send out web content as http but have no way of issuing ssl certificates, its not a problem. The reverse proxy handles that part of the connection in the local services stead. The reverse proxy part is a little complicated to understand, but it becomes clear what it does the more you think about it (which is true of most things I guess). Its an important part of modern internet infastructure that helps give your network a boost in security and configurability.
I choose caddy as a reverse proxy and https encryption certificate server instead of nginx+certbot because I was told it was easier to configure. Caddy has automatic https already setup. The caddyfile config promised to not being a nightmare-slog to read through or configure from scratch. Im not used to this kind of thing so I went with the option that promised easiest implementation with the essential features I really needed.
Nginx has some things out of the box caddy doesn't but by the time I get to needing them ill probably be comfortable enough to wrangle with configs without getting stressed out. At the end of the day I wanted to get something working and start making content, not wrangle with grainular infrastructure configs for hours just for something to break.
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
This is the real caddyfile I am using for my site tomcon.net. It took a bit of figuring out on my part how to properly format everything, the caddy docs help but not enough. I hope sharing this serves you well in your own site building journey.
# The Caddyfile is an easy way to configure your Caddy web server. # # Unless the file starts with a global options block, the first # uncommented line is always the address of your site. # # To use your own domain name (with automatic HTTPS), first make # sure your domain's A/AAAA DNS records are properly pointed to # this machine's public IP, then replace ":80" below with your # domain name. tomcon.net { header { # Content Security Policy (adjust to your needs) Content-Security-Policy " default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; frame-src 'none'; upgrade-insecure-requests; " # XSS Protection X-XSS-Protection "1; mode=block" # Prevent MIME sniffing X-Content-Type-Options "nosniff" # Frame options X-Frame-Options "SAMEORIGIN" # Referrer policy Referrer-Policy "strict-origin-when-cross-origin" # Feature policy (now mostly replaced by Permissions-Policy) Permissions-Policy "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()" # Remove server header -Server } header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" # Set this path to your site's directory. root * /var/www/html # Enable the static file server. file_server # Another common task is to set up a reverse proxy: reverse_proxy localhost:8080 # Or serve a PHP site through php-fpm: # php_fastcgi localhost:9000 tls my-email@redacted.com } ai.tomcon.net { tls my-email@redacted.com reverse_proxy http://10.0.0.53:5005 header { # Content Security Policy (adjust to your needs) Content-Security-Policy " default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; frame-src 'none'; upgrade-insecure-requests; " # XSS Protection X-XSS-Protection "1; mode=block" # Prevent MIME sniffing X-Content-Type-Options "nosniff" # Frame options X-Frame-Options "SAMEORIGIN" # Referrer policy Referrer-Policy "strict-origin-when-cross-origin" # Feature policy (now mostly replaced by Permissions-Policy) Permissions-Policy "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()" # Remove server header -Server } header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" }
Caddy stores a cert and key pair for each registered domain+subdomain here:
/home/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory
Once you have caddy and apache2 setup, go into your router and find the port forwarding configuration settings. Make note of your caddy+apache servers local IP address, and forward the ports 80/TCP and 443/TCP. Save. These are the standard ports for http and https which web browsers quietly knock on to connect to. Youve just exposed them for external connection. Instead of directly connecting to apache, caddy claims these ports in apaches stead so all external connections go through caddy first. Apache sends html to caddy on port 8080, caddy adds certificates and passes the data to the external client. Neat!
Once your site has https and is externally connectable, Go to securityheaders.com and mozilla observatory to get your site tested for header hardening. You want as high a score as you can manage. The headers included in the caddyfile I provided are enough to get tomcon.net at a near-perfect score.
allow ports in UFW
sudo ufw allow http sudo ufw allow https sudo ufw allow 80 sudo ufw allow 443
sudo ufw reload sudo ufw enable sudo ufw reload
sudo systemctl enable ufw
Fail2ban helps deal with potential issues related to brute force attacks. It monitors connections and if one client tries to connect too many times too quickly it triggers a temp ban or 'jails' the IP for a time.
This is the entire related bash history containing all the terminal commands I put in up to the point the site came online. This doesn't reflect everything done as some actions were through the GUI like editing configs. Nonetheless, it should help give you an idea of the simple workflow and testing it took to set up tomcon.net from a base linux mint cinnamon install.
1 ifconfig 2 sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https 3 curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg 4 curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list 5 sudo apt update 6 sudo apt install caddy 7 sudo nano /etc/caddy/Caddyfile 8 sudo systemctl reload caddy 9 sudo systemctl enable caddy 10 sudo systemctl status caddy 11 sudo systemctl reload caddy 12 sudo systemctl status caddy 13 sudo ufw allow http 14 sudo ufw allow https 15 sudo ufw allow 80 16 sudo ufw allow 443 17 sudo ufw reload 18 sudo ufw enable 19 sudo ufw reload 20 sudo caddy validate --config /etc/caddy/Caddyfile 21 sudo systemctl reload caddy 22 sudo systemctl status caddy 23 sudo caddy validate --config /etc/caddy/Caddyfile 24 caddy fmt --overwrite 25 caddy fmt --overwrite /etc/caddy/caddyfile 26 caddy fmt --overwrite etc/caddy/caddyfile 27 caddy fmt --overwrite etc/caddy/Caddyfile 28 caddy fmt --overwrite /etc/caddy/Caddyfile 29 sudo systemctl reload caddy 30 sudo caddy validate --config /etc/caddy/Caddyfile 31 curl -I http://localhost 32 sudo systemctl status caddy 33 sudo systemctl reload caddy 34 sudo systemctl status caddy 35 sudo systemctl reload caddy 36 sudo systemctl status caddy 37 sudo systemctl reload caddy 38 nano /etc/host 39 sudo nano /etc/host 40 sudo nano /etc/hosts 41 sudo systemctl reload caddy 42 sudo systemctl status caddy 43 sudo systemctl reload caddy 44 sudo systemctl status caddy 45 sudo systemctl reload caddy 46 sudo systemctl status caddy 47 sudo apt install apache2 48 sudo systemctl enable apache2 49 sudo systemctl status apache2 50 sudo systemctl enable apache2 51 sudo systemctl start apache2 52 sudo systemctl status apache2 53 systemctl reload caddy 54 sudosystemctl reload caddy 55 sudo systemctl reload caddy 56 sudo systemctl status caddy 57 sudo lsof -i :80 58 sudo nano /etc/hosts 59 sudo systemctl status caddy 60 ifconfig 61 sudo systemctl reload caddy 62 sudo systemctl status caddy 63 sudo ufw allow 8080 64 sudo systemctl reload caddy 65 sudo systemctl status caddy 66 sudo lsof -i :80 67 sudo lsof -i :8080 68 sudo systemctl status caddy 69 sudo journalctl -u caddy --since 10 minutes ago 70 sudo journalctl -u caddy --since "10 minutes ago" 71 sudo journalctl -u caddy 72 sudo systemctl reload apache2 73 sudo a2enmod headers 74 systemctl restart apache2 75 sudo systemctl apache2 76 sudo a2enmod headers 77 sudo systemctl restart apache2 78 sudo systemctl reload apache2 79 sudo systemctl restart apache2 80 sudo systemctl restart caddy 81 sudo systemctl reload caddy 82 sudo systemctl restart caddy 83 sudo systemctl reload caddy 84 sudo systemctl restart caddy 85 sudo systemctl reload caddy 86 sudo systemctl status caddy 87 sudo systemctl reload caddy 88 sudo systemctl status caddy 89 sudo systemctl restart caddy 90 sudo systemctl status caddy 91 sudo systemctl reload caddy 92 sudo caddy validate --config /etc/caddy/Caddyfile 93 caddy fmt --overwrite /etc/caddy/caddyfile 94 caddy fmt --overwrite /etc/caddy/Caddyfile 95 sudo caddy validate --config /etc/caddy/Caddyfile 96 sudo systemctl reload caddy 97 sudo systemctl restart caddy 98 sudo systemctl reload caddy 99 sudo systemctl status caddy 100 sudo systemctl reload caddy 101 sudo systemctl restart caddy 102 sudo systemctl status caddy 103 sudo journalctl -u caddy --since 10 minutes ago 104 sudo journalctl -u caddy --since "10 minutes ago" 105 sudo apt install fail2ban 106 sudo systemctl restart caddy 107 sudo systemctl reload caddy 108 sudo journalctl -u caddy --since "5 minutes ago" 109 sudo systemctl restart caddy 110 sudo systemctl reload caddy 111 sudo journalctl -u caddy --since "5 minutes ago" 112 caddy fmt --overwrite /etc/caddy/Caddyfile 113 sudo systemctl restart caddy 114 sudo systemctl reload caddy 115 sudo caddy validate --config /etc/caddy/Caddyfile 116 cat ~/.bash_history 117 sudo nano /etc/hosts 118 sudo systemctl enable fail2ban 119 systemctl start fail2ban 120 sudo systemctl status caddy 121 sudo journalctl caddy 122 sudo journalctl -u caddy | grep -i acme 123 sudo journalctl -u caddy 124 systemctl status ufe 125 systemctl status ufw 126 sudo ufw enable
The gemini protocol aspect of this site is powered by a simple Agate server written in Rust. Gemini is a small-net protocol designed for simplicity in implimentation and text formatting. It may be accessed using native browser software or web based proxies.
Visit agates git and download the precompiled binary.
put the program into /bin
open a new bash instance, run the following
sudo agate --hostname your-domainname.com --addr 10.0.0.xx:1965 --content /home/user/gemini/gemtext
If all goes well the agate server should start up fine.