Notes on setting up Ubuntu 19.10

##################
### PuTTY
# Windows app to connect to your server via secure sockets SSH
# https://www.putty.org

# Download Ubuntu ISO
# Make a bootable USB stick using Rufus on a windows computer
# When installing Ubuntu don't tick everything, you can apt install it later

##################
### Fix ipv6
# Disable IPV6, only IPv4 in my house!
# https://support.purevpn.com/how-to-disable-ipv6-linuxubuntu
sudo nano /etc/sysctl.conf
# Paste the following at the end
#--- file: /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
#---
sudo sysctl -p
# Test with the following
cat /proc/sys/net/ipv6/conf/all/disable_ipv6
# Should report 1, else shutdown -r now

##################
# Switch Update Source
# For some reason au sources don't work, back them up
# cannot initiate the conection to au.archive.ubuntu.com:80
ls /etc/apt
cp /etc/apt/sources.list /etc/apt/sources.list.au
# replace them with curtin version
cp /etc/apt/sources.list.curtin.old /etc/apt/sources.list
# Test with
apt update

##################
### Updating Ubuntu OS
# sudo do-release-upgrade # upgrade to newest version of Ubuntu (danger!)
sudo apt update        # Fetches the list of available updates
apt list --upgradeable
sudo apt upgrade       # Installs some updates; does not remove packages
sudo apt full-upgrade  # Installs updates; may also remove some packages, if needed
sudo apt autoremove    # Removes any old packages that are no longer needed
sudo apt-get dist-upgrade -y
sudo apt-get autoclean -y
#
apt update
apt upgrade

##################
### BASHRC
nano ~/.bashrc
#--- File: ~/.bashrc
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias sc='systemctl'
alias ..='cd ..'
alias rd='rmdir'
alias md='mkdir'
alias web='cd /var/www/html'
alias cwd='pwd'
alias bashrc='pico ~/.bashrc'
#---

##################
### Install various utilities
sudo apt -y install net-tools cifs-utils locate sendmail mutt
# Or each individually:
sudo apt -y install net-tools
# sudo apt -y install smbclient
sudo apt -y install cifs-utils
sudo apt -y install unzip 
sudo apt -y install zip
sudo apt -y install locate
sudo apt -y install sendmail
sudo apt -y install mutt
sudo apt -y install nbtscan
sudo apt -y install nmap
sudo apt -y install samba
sudo apt -y install mergelog

### NBTScan
# check logged in devices responding to NBT
nbtscan 192.168.0.1-255 -t3

### NMAP
nmap -sP 192.168.0.0/24

### FIREWALL
# block SMB connections from everywhere except local network
iptables -A INPUT -j DROP ! -s 192.168.0.0/24 -m multiport -p tcp --dports 139,445

### HOSTNAME
# single sessions
hostname mydyndnsname.net
# permanent
hostnamectl set-hostname mydyndnsname.net

### Local time zone
# timedatectl
# ls /usr/share/zoneinfo
# Check time details
timedatectl status
# Set time zone
sudo timedatectl set-timezone Australia/Brisbane

### Check network config
ifconfig

### Update root password
sudo passwd root
su

### Version
uname -srm
uname --kernel-name --kernel-release --machine
cat /etc/os-release
lsb_release -a

#########################
### MOUNT SHARES
# How to access SMB share on another computer
# list shares on 192.168.0.33
# You need to install cifs once first
apt -y install cifs-utils

# Make a main mount folder
# then make a folder for each share you want to connect to
mkdir /zuko
mkdir /zuko/nuc
mkdir /zuko/web
mkdir /zuko/photo

# Manual temporary connect to smb share / lost at reboot
mount -t cifs //192.168.0.222/nuc /zuko/nuc -o username=eddie
mount -t cifs //192.168.0.222/web /zuko/web -o username=eddie
mount -t cifs //192.168.0.222/photo /zuko/photo -o username=eddie

# Unmount / umount the share from your linux folders
umount /zuko/nuc
umount /zuko/web
umount /zuko/photo

### SCRIPT: CONNECT TO SHARED FOLDERS
# You might want to connect to shares a lot:cd  make a script
nano /home/eddie/cifs
#--- File: ~/cifs
echo Connecting external shares to local mounts
echo \/zuko\/nuc
mount -t cifs //192.168.0.222/nuc /zuko/nuc -o username=eddie
echo \/zuko\/web
mount -t cifs //192.168.0.222/web /zuko/web -o username=eddie
#--- END File

# Make the script executable
chmod 755 ~/cifs
~/cifs

# create a link to cifs when logged in as root
# i.e. your home folder is elsewhere
# create ~/cifs file that is a link to /home/eddie/cifs
ln -s /home/eddie/cifs ~/cifs

#########################
### PERMISSIONS / OWNERSHIP
### Users
less /etc/passwd
cut -d: -f1 /etc/passwd
adduser eddie
deluser eddie
userdel username : deletes a user
# chage : chage password expiry

### Groups
# LIST groups
cat /etc/group
sort /etc/group | awk -F: '{ print $1}'
# LIST groups for specific user (default = current user)
groups eddie
# CREATE a new group
groupadd web
# ADD user eddie to group group.
# -G will remove all prior groups and replace with specified group
# -aG will append group to user's list of groups
usermod -aG www-data eddie
# RENAME a group (-n name)
groupmod -n newname oldname
# chgrp : change group ownership of the file
# gpasswd : administer the /etc/group file
# groupdel mygrp : Delete a new group 
# newgroup mygrp : USER change default group
# eddie : eddie adm cdrom sudo dip plugdev lxd www-data

# user www-data, group www-data

chown root:www-data -R /var/www/html/dev
chmod -R 775 /var/www/html/dev
sudo chown -R nobody:nogroup /mnt/share

#########################
### SAMBA
# Share folders with windows/mac computers
# not: gksu
sudo apt-get install -y samba
# Log
less -S /var/log/samba/log.smbd
less -S /var/log/samba/log.nmbd

# status restart start stop
systemctl restart smbd
systemctl restart nmbd

smbpasswd -a eddie

nano /etc/samba/smb.conf
#--- File: /etc/samba/smb.conf
[wwwdev]
path = /var/www/html/dev/
available = yes
valid users = @www-data
read only = no
browsable = yes
public = no
writable = yes
create mask = 0775
force user = www-data
force group = www-data
#---

#########################
# LAMP
# Apache, MySQL, PHP
sudo apt install lamp-server^

# status restart stop start
systemctl status apache2
systemctl status mysql

# You should now see the demo web page
# http://mydyndnsname.net
# http://192.168.0.54
# or whatever your ip is: ifconfig
### INI/CONF FILES
nano /etc/php/7.3/apache2/php.ini
nano /etc/apache2/apache2.conf
nano /etc/mysql/mysql.conf.d/mysqld.cnf

### LOG FILES
# Note: G in less takes to end
less -S /var/log/mysql/error.log
less -S /var/log/apache2/error.log
less -S /var/log/apache2/access.log
less -S /var/log/samba/log.smbd
less -S /var/log/samba/log.nmbd
#/var/log/apache2/ --> PHP, WWW
#/var/log/mysql/
#/var/log/auth.log
#/var/log/syslog/

### SCRIPT: LOG FILE COPY
# Copy logs to a cifs mounted share
mkdir /zuko/nuc
nano ~/logcp
#--- File: ~/logcp
cp /var/log/mysql/error.log /zuko/nuc/mysql_error.log
cp /var/log/apache2/error.log /zuko/nuc/apache2_error.log
cp /var/log/apache2/access.log /zuko/nuc/apache2_access.log
cp /var/log/samba/log.smbd /zuko/nuc/smbd_s.log
cp /var/log/samba/log.nmbd /zuko/nuc/smbd_n.log
cp /var/log/auth.log /zuko/nuc/auth.log
cp /var/log/syslog /zuko/nuc/syslog.log
#--- END File
chmod 755 ~/logcp
~/logcp

##################
### APACHE
# Your web files /var/www/html
chown root:www-data -R /var/www/html
chmod -R 775 /var/www/html/dev
# chown root:root -R /var/www/html

# Security
# Options Includes Indexes FollowSymLinks MultiViews
# "Indexes" allows folders to be displayed / navigated
# Remove "Indexes" from Options within <Directory /var/www/> section
nano /etc/apache2/apache2.conf
#--- File: /etc/apache2/apache2.conf
<Directory /var/www/>
        Options FollowSymLinks
        AllowOverride None
        Require all granted
</Directory>
#---
systemctl restart apache2

ls /etc/apache2/sites-available/
ls /etc/apache2/sites-enabled/

## Example sites available formats
#--- File: /etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:80>
	#ServerName www.example.com
	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/html
	# Available loglevels: 
	#trace8 ... trace1, debug, info, notice, warn, error, crit, alert, emerg
	#LogLevel info ssl:warn
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
	#Include conf-available/serve-cgi-bin.conf
</VirtualHost>
#---
# Example LimeSurvey virtual host (why - it is in the default host path?)
#--- File: /etc/apache2/sites-available/limesurvey.conf
<VirtualHost *:80> 
	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/html/limesurvey/
	ServerName limesurvey.com
	ServerAlias www.limesurvey.com
	<Directory /var/www/html/limesurvey/> 
		Options FollowSymLinks
		AllowOverride All
	</Directory> 
	ErrorLog /var/log/apache2/limesurvey-error_log
	CustomLog /var/log/apache2/limesurvey-access_log common
</VirtualHost> 
#---

### Log files
# Change from daily to weekly log files, good for reporting (See also: webalizer)
# WARNING: a moderately active site will generate huge access log files
nano /etc/logrotate.d/apache2
#--- File: /etc/logrotate.d/apache2
/var/log/apache2/*.log {
        weekly
        missingok
        rotate 12
#--- END File
logrotate /etc/logrotate.conf --debug

##################
### PHP Modules
apt install php-mysqlnd php-pdo php-gd php-mbstring php-json php-xml php-zip php-curl
# Error log files
less -S /var/log/apache2/error.log
less -S /var/log/apache2/access.log

nano /etc/php/7.3/apache2/php.ini
#--- File: /etc/php/7.3/apache2/php.ini
; Note display_errors is mentioned in multiple places but should be uncommented in only one
; You'll want to turn display_errors off after your system is fully configed
display_errors = On
mail.add_x_header = Off
max_input_vars = 12000
memory_limit = 3072M
upload_max_filesize = 700M
max_file_uploads = 32
post_max_size = 700M
#--- END File
systemctl restart apache2

# You will want to add this to the beginning of your PHP code if you want errors displayed.
# In addition to above PHP.ini settings
#--- File: *.php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
#--- END File

##################
### MySQL config
# MySQL is active on port 3306 by default, however firewall prevents access.
# Install MySQLWorkbench on workstation

less -S /var/log/mysql/error.log

nano /etc/mysql/mysql.conf.d/mysqld.cnf
#--- File: /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
default-authentication-plugin=mysql_native_password
# * Basic Settings
user            = mysql
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
port            = 3306
datadir         = /var/lib/mysql
innodb_buffer_pool_size=2G
bind-address    = 0.0.0.0
#--- END File
systemctl restart mysql

mysql -u root
# Set local root user password
ALTER USER 'root'@'localhost' IDENTIFIED BY 'XXww%vg6oA-5MwtF44&';
# @localhost can't logon remotely

select * from mysql.user \G
# Add remote user and privs
CREATE USER 'eddie'@'192.168.0.0/255.255.0.0' IDENTIFIED BY 'vg6oAXXww%A-5MwtQML';
GRANT ALL PRIVILEGES ON *.* TO 'eddie'@'192.168.0.0/255.255.0.0' WITH GRANT OPTION; 
## PROBLEMS connecting to MySQL from Workbench includes the network mask above. 
# Ensure that ip can fit within mask.

alter user 'username'@'localhost' identified with mysql_native_password by 'password';

##################
### WORDPRESS - Blog
# https://help.ubuntu.com/lts/serverguide/wordpress.html
apt install wordpress
# ls /var/lib/wordpress/
# ls /usr/share/wordpress/
# Edit the wordpress config
nano /etc/apache2/sites-available/wordpress.conf
#--- File: /etc/apache2/sites-available/wordpress.conf
Alias /blog /usr/share/wordpress
<Directory /usr/share/wordpress>
	Options FollowSymLinks
	AllowOverride Limit Options FileInfo
	DirectoryIndex index.php
	Order allow,deny
	Allow from all
</Directory>
<Directory /usr/share/wordpress/wp-content>
	Options FollowSymLinks
	Order allow,deny
	Allow from all
</Directory>
#---
#Enable the site
sudo a2ensite wordpress
systemctl reload apache2
# Wordpress config
#    /etc/wordpress/config-mydyndnsname.net.php
#	 /etc/wordpress/config-localhost.php
cp /usr/share/wordpress/wp-config-sample.php /etc/wordpress/config-default.php
nano
#--- File: /etc/wordpress/config-default.php
# Add the line
define( 'FS_METHOD', 'direct' );

chown root:www-data -R /usr/share/wordpress/wp-content
chmod -R 775 /usr/share/wordpress/wp-content

mysql -u root
#--- MySQL commands
CREATE USER wordpress@localhost IDENTIFIED BY 'yourPWDhere';
ALTER USER 'wordpress'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourPWDhere';
CREATE DATABASE wordpress;
GRANT ALL PRIVILEGES ON wordpress.* TO wordpress@localhost;
#---
http://mydyndnsname.net/blog/wp-admin/install.php

less -S /var/log/mysql/error.log
less -S /var/log/apache2/error.log
less -S /var/log/apache2/access.log

##################
# Webmin - System management
# Download the deb file
# http://www.webmin.com/download.html
# -- 
# copy to \\192.168.0.222\nuc\~Linux
sudo apt install /zuko/nuc/~Linux/webmin_1.930_all.deb
# https://192.168.0.54:10000

##################
# Adminer - basic SQL management
# WARNING: Does not accept MySQL8 passwords, need mysql_nativie_password in mysqld.cnf
apt install -y adminer
# /etc/adminer/conf.php
# /usr/share/adminer/
# not required: chown root:www-data -R /usr/share/adminer
# not required: chmod -R 775 /usr/share/adminer
### Build virtual folder config file
nano /etc/apache2/sites-available/adminer.conf
#--- File: /etc/apache2/sites-available/adminer.conf
Alias /adminer /usr/share/adminer
<Directory /usr/share/adminer>
	Options FollowSymLinks
	AllowOverride Limit Options FileInfo
	DirectoryIndex index.php adminer.php
	Order allow,deny
	Allow from all
</Directory>
#---
#Enable the site
a2ensite adminer
systemctl reload apache2

# NOTE Adminer requires mysql_native_password
# this can be set in mysqld.cnf (see mysql above) otherwise ... ALTER
CREATE USER eddie@localhost IDENTIFIED BY 'yourPWDhere';
ALTER USER eddie@localhost IDENTIFIED WITH mysql_native_password BY 'yourPWDhere';
GRANT ALL PRIVILEGES ON *.* TO eddie@localhost;
GRANT ALL PRIVILEGES ON *.* TO root@localhost;
ALTER USER root@localhost IDENTIFIED WITH mysql_native_password BY 'yourROOTPWDhere';

### SQL UTILITY COMMANDS
select * from mysql.user \G
show databases;
use mysql;
show tables;
select * from db;
select * from db \G    # vertical display of table
select @@innodb_buffer_pool_size/1024/1024/1024;

##################
### Webalizer - Web stats
# Ugly web site log analyser, very basic
# Webalizer can only handle one log file at a time
# (a) mergelog to join logfiles
# (b) set logrotate to weekly instead of daily for apache
# Note apache will gzip 3rd+ log files which cannot be merged (easily)
apt install webalizer
apt -y install mergelog
# /var/www/webalizer
mv /var/www/webalizer /var/www/html/
chown root:www-data -R /var/www/html/webalizer
chmod 774 /var/www/html/webalizer
nano /etc/webalizer/webalizer.conf
# Ensure the following settings are set correctly (LogFile, OutputDir)
#--- File: /etc/webalizer/webalizer.conf
#LogFile /var/log/apache2/access.log
#LogFile /var/log/apache2/access.log.1
OutputDir /var/www/html/webalizer
#--- END File

mergelog /var/log/apache2/access.log /var/log/apache2/access.log.1 | webalizer
/usr/bin/mergelog /var/log/apache2/access.log /var/log/apache2/access.log.1 | /usr/bin/webalizer -c /etc/webalizer/webalizer.conf > /var/log/apache2/webalizer.log

nano /etc/logrotate.conf
nano /etc/logrotate.d/apache2
#--- File: /etc/logrotate.d/apache2
/var/log/apache2/*.log {
        weekly
        missingok
        rotate 12
#--- END File
logrotate /etc/logrotate.conf --debug

# Remove cron.daily script
mv /etc/cron.daily/webalizer /etc/webalizer/webalizer.cron.daily

# CRON 11:55pm run webalizer
# Line if LogFile is specd in webalizer.conf
# 55 23   * * *   root    /usr/bin/webalizer -c /etc/webalizer/webalizer.conf > /dev/null
# Line if LogFile is commented out in webalizer.conf - i.e. mergelog
# 55 23   * * *   root    /usr/bin/mergelog /var/log/apache2/access.log /var/log/apache2/access.log.1 | /usr/bin/webalizer -c /etc/webalizer/webalizer.conf > /dev/null
# Wait - /etc/cron.daily has locate, webalizer scripts
nano /etc/crontab
#--- File: /etc/crontab
55 23   * * *   root    /usr/bin/mergelog /var/log/apache2/access.log /var/log/apache2/access.log.1 | /usr/bin/webalizer -c /etc/webalizer/webalizer.conf > /var/log/apache2/webalizer.log
#---
systemctl status cron

##################
### AWStats - Web stats
# Bloody ugly web site log analyser
# https://awstats.sourceforge.io/
# https://linuxwebdevelopment.com/how-to-setup-awstats-for-a-domain-in-debian-jessie/
# https://awstats.sourceforge.io/docs/awstats_setup.html
# http://mydyndnsname.net/awstats
###
# /etc/awstats
# /usr/bin/awstats
# /etc/default/awstats
# /usr/share/awstats
# ll /usr/share/doc/awstats/
apt -y install awstats
#
ln -s /var/log/apache2/access.log /var/lib/awstats/access.log
mkdir /var/www/html/awstats
chown root:www-data -R /var/www/html/awstats
chmod -R 775 /var/www/html/awstats
chown root:www-data -R /var/lib/awstats/
# chmod -R 775 /var/lib/awstats/
chown root:www-data -R /usr/share/awstats/icon/
#
nano /etc/awstats/awstats.conf
#--- File: /etc/awstats/awstats.conf
SiteDomain="mydyndnsname.net"
LogFile="/var/lib/awstats/access.log"
HostAliases="localhost 127.0.0.1 mydyndnsname.net myotherdomain.com another.com"
DirData="/var/lib/awstats"
DirCgi="/awstats/cgi-bin"
DirIcons="/awstats/awstats-icon"
StyleSheet="/awstats/aws-css"
SkipHosts="REGEX[^192\.168\.]"
Include "/etc/awstats/awstats.conf.local"
#--- END File

nano /etc/apache2/sites-available/awstats.conf
#--- File: /etc/apache2/sites-available/awstats.conf
Alias /awstatsclasses "/usr/share/awstats/lib/"
#Alias /awstats/aws-classes "/usr/share/awstats/lib/"
#Alias /awstats-icon "/usr/share/awstats/icon/"
Alias /awstats/aws-icon "/usr/share/awstats/icon/"
#Alias /awstatscss "/usr/share/doc/awstats/examples/css"
Alias /awstats/aws-css "/usr/share/doc/awstats/examples/css"
#ScriptAlias /awstats/ /usr/lib/cgi-bin/
ScriptAlias /awstats/cgi-bin "/usr/lib/cgi-bin/"
#
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
<Directory "/usr/lib/cgi-bin/">
        Options FollowSymLinks
        AllowOverride Limit Options FileInfo
        DirectoryIndex index.php index.html
        Order allow,deny
        Allow from all
</Directory>
#--- END File
a2ensite awstats
systemctl restart apache2

# Change cron permissions from www-data to root
# Change from every 10 minutes to ever 8 hours
cat /etc/cron.d/awstats
nano /etc/cron.d/awstats
#--- File: /etc/cron.d/awstats
MAILTO=root
* */8 * * * root [ -x /usr/share/awstats/tools/update.sh ] && /usr/share/awstats/tools/update.sh
# Generate static reports:
10 03 * * * root [ -x /usr/share/awstats/tools/buildstatic.sh ] && /usr/share/awstats/tools/buildstatic.sh
#--- END File

nano /var/www/html/awstats/index.php
#--- File: /var/www/html/awstats/index.php
<HTML><HEAD><TITLE>AWStats</TITLE></HEAD><BODY><iframe src="cgi-bin/awstats.pl" style="position:fixed; top:0; left:0; bottom:0; right:0; width:100%; height:100%; border:none; margin:0; padding:0; overflow:hidden; z-index:999999;">
<a href="cgi-bin/awstats.pl">AWStats</a>
</iframe></BODY></HTML>
#--- END File
# http://mydyndnsname.net/awstats

apt --purge remove awstats



##################
# BACKUP
# https://help.ubuntu.com/community/BackupYourSystem
# Way more difficult in a mixed system environment than it should be.
# But then Linux is way more difficult than it should be.

### TAR
# https://help.ubuntu.com/community/BackupYourSystem/TAR
# http://mydyndnsname.net/LinuxBackupTAR.html
nano /usr/local/bin/backup
#--- File: /usr/local/bin/backup
# Backup entire drive using RSYNC
# /var/log/backup.log
LOGFILE=/var/log/backup.log
echo "### Backup started $(date)" >> $LOGFILE
cd /
tar -cvpzf /zuko/nuc/backup/backup.tar.gz \
--exclude=/dev \
--exclude=/proc \
--exclude=/sys \
--exclude=/tmp \
--exclude=/run \
--exclude=/mnt \
--exclude=/media \
--exclude=/zuko \
--exclude=/swap.img \
--exclude=/var/cache/apt/archives \
--exclude=/home/*/.gvfs \
--exclude=/home/*/.cache \
--exclude=/home/*/.local/share/Trash / >> $LOGFILE
echo "### Backup completed $(date)" >> $LOGFILE
#--- END File

### RSYNC
# RSYNC is a mess for backup, unless you have a target site which translates permissions really well, then just leave this option alone.
# Great for backing up individual files, not good for system restore.
nano /usr/local/bin/backup
#--- File: /usr/local/bin/backup
# Backup entire drive using RSYNC
# /var/log/backup.log
LOGFILE=/var/log/backup.log
echo "### Backup started $(date)" >> $LOGFILE
# sudo rsync -aAXv / --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/zuko/*","/lost+found","/var/www/html/ph/*"} /zuko/nuc/backup/ >> $LOGFILE
sudo rsync -aAX / --exclude={/dev,/proc,/sys,/tmp,/run,/mnt,/media,/zuko,/lost+found,/var/www/html/ph,/swap.img} /zuko/nuc/backup/ >> $LOGFILE
echo "### Backup completed $(date)" >> $LOGFILE
#--- END File

### DD
# Whole Partition into a file(s)
# You need a bootable Linux from USB to run this, and a mountable backup target from your booted Linux.
# https://unix.stackexchange.com/questions/226144/creating-a-snapshot-of-a-linux-system/226161
# Clone your linux drive using a live system from USB (example Ubuntu from a USB thumb drive)
# Copy your hard disk to an external hard drive - partition to partition
dd if=/dev/sda1 bs=64M of=/mnt/my_external_backup_drive/backup-sda1
# where you need to replace /dev/sda1 with your root (/) partition.
# Do the same with other partitions (like the one for /boot, /boot/efi, /home) where applicable.
# If you need to save space, you could do
dd if=/dev/sda1 bs=64M | gzip --fast | dd bs=32M of=/mnt/my_mounted_backup_drive/backup-sda1.gz
## TAR : more complicated, much slower but saving a few more bytes,
mkdir -p /mnt/linux
mount -o ro /dev/sda1 /mnt/linux
cd /mnt/linux
tar cvJf /mnt/my_mounted_backup_drive/linux-backup.tar.xz .??* *
## RESTORE
mkdir -p /mnt/linux
mount /dev/sda1 /mnt/linux
cd /mnt/linux
tar xvJf /mnt/my_mounted_backup_drive/linux-backup.tar.xz
# or
dd /mnt/my_mounted_backup_drive/backup-sda1.gz bs=32M | gzip --decompress | dd bs=64M of=/dev/sda1
# (careful where you are writing your data, this deletes everything on /dev/sda1, so get it right the first time)