3rd migration complete ✌ . New era, new Docker stack
After 12 year I'm still here and, finally I did it, the 3rd big self hosted migration✌.
Nope, my VPS isn't so busy. Just generated some traffic to make it look cooler.
When I started the word "blog" didn't exist yet and internet was a mix of forums and websites, now it's full of social, videos and many people stopped to self host "things" because they prefere something that just works™ that they don't have to mantain. The funny fact it's has never been years to self host a web software as today!
Linux, DNS, reverse proxy, HTTPS, PHP, NodeJS, CMS, VPN, ssh, to self host even a stupid kitten blog, you have to wire a lot of tech, most technologies are open source but you have to know what you are doing and it's your responsibility to check that they continue talk fine even after upgrades. ..And it's not easy to follow any possible stack permutation!
OK, I've a landing page, how a deploy can be easier?
Let's say you have a new web page in
./app/index.html and you want to publish it on on the Internet.. to
https://make-self-hosting-great-again.grigio.org what do you do?
It can be easy as using a
docker-compose.yml file and run a command!
# docker-compose.yml version: "3" services: app: image: busybox restart: unless-stopped volumes: - ./app:/var/www networks: - web labels: - traefik.docker.network=web - traefik.frontend.rule=Host:make-self-hosting-great-again.grigio.org - traefik.port=9000 - traefik.backend=msgh entrypoint: busybox httpd -f -p 0.0.0.0:9000 -h /var/www networks: web: external: true
docker-compose up -d
And we are live! https://make-self-hosting-great-again.grigio.org
dig subdomain.yourdomain.comthat the DNS propagation is complete, it could take some minutes. You should see the name resolved your IP. With
A * YOUR.VPS.IPYou can resolve all subdomains.
Sometimes the HTTPS / Traefik / Letsencrypt certificate is not valid, you have to wait or try an anonymous session in the browser.. because it isn't updated on every request, at least on Chrome.
webis used by Traefik to automagically generate the HTTPS certificate, you could also use a network to share a database name resolution among multiple containers.
Making things simple is hard
To be honest, I tried several times in the past to do this migration, and I failed. At the time docker was immature to my needs but now it's another story. Here is a list of things of my pains:
Ideally docker containers are stateless, but some projects, specially old CMS mix app, config, plugins, web server extensions, database configs (ex. mod_rewrite for clean urls,..). There isn't a perfect solution, you can always mount that blob and use the container to freeze the stack.
Projects with not clear dependencies are pain. I had problems with old versions of Drupal 4 /6 and Meteor 1.0.3.x Stacks evolves and also Databases and you have to replicate the exact version to port them.
mysqldumpis a pain, it did a backup of a database with a corrupt table without errors.. but the dump ignored halt of the tables -_-
Thanks to the open source and docker ecosystem
Here some docker images I use:
- Reverse Proxy: Traefik
traefik:alpineIt is the only gateway to manage websites traffic and HTTPS certs renewal (port 80/443)
- Container management web UI: Portainer
portainer/portainerTo have a visual feedback of
- System performance overview: Netdata
- Email aliases
- VPN server
- .. and more but with weird customizations
Some beautyful oneliners..
It creates a temporary mysql container to extract a database backup
docker run --net web -v $PWD/backup:/backup --rm -i mysql:5.7 sh -c "MYSQL_PWD=yourpassword mysqldump -h mysqlinstance -u yourdbuser yourdatabase | gzip -9 > /backup/dbbackup.sql.gz"
It attaches to mysql container to restore a database backup
docker exec -i mysqlinstance /usr/bin/mysql -u root --password=yourrootpassword -e "create database yourdatabase" gunzip < backup/dbbackup.sql.gz | docker exec -i mysqlinstance /usr/bin/mysql -u yourdbuser --password=yourpassword yourdatabase
I hope you like it, the cloud isn't just Amazon AWS and Google.